diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/nthals/halsnip/mips | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to 'private/ntos/nthals/halsnip/mips')
45 files changed, 22761 insertions, 0 deletions
diff --git a/private/ntos/nthals/halsnip/mips/allstart.c b/private/ntos/nthals/halsnip/mips/allstart.c new file mode 100644 index 000000000..07274b604 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/allstart.c @@ -0,0 +1,65 @@ +/*++ + +Copyright (c) 1993 - 1994 Siemens Nixdorf Informationssysteme AG +Copyright (c) 1994 Microsoft Corporation + +Module Name: + + allstart.c + +Abstract: + + + This module implements the platform specific operations that must be + performed after all processors have been started. + +--*/ + +#include "halp.h" +#include "string.h" + + +BOOLEAN +HalAllProcessorsStarted ( + VOID + ) + +/*++ + +Routine Description: + + This function executes platform specific operations that must be + performed after all processors have been started. It is called + for each processor in the host configuration. + + Note: this HAL is for the Siemens Nixdorf Uni-/MultiProcessor Computers + +Arguments: + + None. + +Return Value: + + If platform specific operations are successful, then return TRUE. + Otherwise, return FALSE. + +--*/ + +{ + + + if (HalpIsTowerPci){ + + // on PCI tower, MAUI_INT is on processor number 1 if more than one processor + + if ((PCR->Number == 1) || (HalpIsMulti == 0 )){ + + HalpCreateIntPciMAUIStructures(PCR->Number); + HalpInitMAUIMPAgent(); + + } + } + + return TRUE; + +} diff --git a/private/ntos/nthals/halsnip/mips/cacherr.s b/private/ntos/nthals/halsnip/mips/cacherr.s new file mode 100644 index 000000000..c0ea29908 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/cacherr.s @@ -0,0 +1,645 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/cacherr.s,v 1.2 1996/02/23 17:55:12 pierre Exp $") +// TITLE("Cache Error Handling") +//++ +// +// Copyright (c) 1993 Microsoft Corporation +// +// Module Name: +// +// cacherr.s +// +// Abstract: +// +// This module implements cache error handling. It is entered in KSEG1 +// directly from the cache error vector wiht ERL set in the processor +// state. +// +// No correction is done. We only try to get the physical address +// that causes this exception +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// +//-- + +#include "halmips.h" + + .globl HalpCacheErrFirst + .globl HalpErrCacheMsg // cache error + .globl HalpParityErrMsg // parity error + .globl HalpAddrErrMsg // no addr found + .globl HalpComputeNum // compute memory sip number + .globl HalpKeBugCheck0 + .globl HalpKeBugCheck1 + .globl HalpKeBugCheck2 + .globl HalpKeBugCheck3 + .globl HalpKeBugCheck4 + .globl HalpBugCheckNumber + +#define CACHE_ERR_ER 0x80000000 +#define CACHE_ERR_EC 0x40000000 +#define CACHE_ERR_ED 0x20000000 +#define CACHE_ERR_ET 0x10000000 +#define CACHE_ERR_ES 0x08000000 +#define CACHE_ERR_EE 0x04000000 +#define CACHE_ERR_EB 0x02000000 +#define CACHE_ERR_EI 0x01000000 +#define CACHE_ERR_SIDX 0x003ffff8 +#define CACHE_ERR_PIDX 0x00000007 +#define PIDX_PD_MASK 0x00001000 // cache size 8k + +#define HALP_OPCODE_MASK 0xfc000000 +#define HALP_OPCODE_SHIFT 24 // because we test opcode number on 8 bits +#define HALP_RT1_REG 0x001f0000 +#define HALP_RT1_SHIFT 16 +#define HALP_RT2_REG 0x03e00000 +#define HALP_RT2_SHIFT 21 + +#define HALP_SWC1 0xe4 // +#define HALP_SDC1 0xf4 // +#define HALP_LWC1 0xc4 // +#define HALP_LDC1 0xd4 // +#define HALP_LB 0x80 // +#define HALP_LH 0x82 // +#define HALP_LW 0x8c // +#define HALP_LD 0xdc // +#define HALP_LBU 0x90 // +#define HALP_LHU 0x94 // +#define HALP_SB 0xa0 // +#define HALP_SH 0xa4 // +#define HALP_SW 0xac // +#define HALP_SD 0xfc // +#define HALP_LWL 0x88 // +#define HALP_LWR 0x98 // +#define HALP_LDL 0x68 // +#define HALP_LDR 0x6c // +#define HALP_LWU 0x9c // +#define HALP_SDL 0xb0 // +#define HALP_SDR 0xb4 // +#define HALP_LL 0xc0 // +#define HALP_LLD 0xd0 // +#define HALP_SC 0xe0 // +#define HALP_SCD 0xf0 // +// +// Define local save area for register state. +// + + .data +SavedAt:.space 4 // saved registers +SavedV0:.space 4 // +SavedV1:.space 4 // +SavedA0:.space 4 // +SavedA1:.space 4 // +SavedA2:.space 4 // +SavedA3:.space 4 // +SavedT0:.space 4 // +SavedT1:.space 4 // +SavedT2:.space 4 // +SavedT3:.space 4 // +SavedT4:.space 4 // +SavedT5:.space 4 // +SavedT6:.space 4 // +SavedT7:.space 4 // +SavedS0:.space 4 // +SavedS1:.space 4 // +SavedS2:.space 4 // +SavedS3:.space 4 // +SavedS4:.space 4 // +SavedS5:.space 4 // +SavedS6:.space 4 // +SavedS7:.space 4 // +SavedT8:.space 4 // +SavedT9:.space 4 // +SavedK0:.space 4 // +SavedK1:.space 4 // +SavedGP:.space 4 // +SavedSP:.space 4 // +SavedS8:.space 4 // +SavedRA:.space 4 // +SavedErrorEpc:.space 4 // +SavedCacheError:.space 4 // + +//++ +// +// VOID +// HalpCacheErrorRoutine ( +// VOID +// ) +// +// Routine Description: +// +// This function is entered from the cache error vector executing +// in KSEG1 and with finished with a fatal system error : +// +// Msg Hal : CACHE ERROR - PARITY ERROR - ADDR IN ERROR NOT FOUND +// KeBugCheckEx : +// a0 = 0x80 Hardware malfunction +// a1 = 18 (parity pb) or 19 (cache error) +// a2 = physical address in error (or 0x00) +// a3 = sim number +// a4 = cacheerror register contents +// +// +// N.B. No state has been saved when this routine is entered. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + .struct 0 + + .struct 0 +CiArgs0:.space 4 // saved arguments +CiArgs1:.space 4 // saved arguments +CiArgs2:.space 4 // saved arguments +CiRa: .space 4 // saved return address +CiFrameLength: // + + NESTED_ENTRY(HalpCacheErrorRoutine, CiFrameLength, zero) + + + subu sp,sp,CiFrameLength // allocate stack frame + sw ra,CiRa(sp) // save return address + + PROLOGUE_END + +// +// Save volatile registers needed to fix cache error. +// + + .set noreorder + +// +// Protection to avoid to execute twice in multipro +// (modif of psr doesn't seem very effective) +// + + la k0,HalpCacheErrFirst + li k1,KSEG1_BASE // convert address of KSEG1 address + or k1,k0,k1 // + lw k0,0(k1) + nop + beq k0,zero,1f + nop + +// cache error during cache error routine + lw ra,CiRa(sp) // save return address + addu sp,sp,CiFrameLength // allocate stack frame + eret // hope we don't need k0 and k1... + nop + +1: add k0,k0,0x01 + sw k0,0(k1) + +// +// Save all the registers +// + + la k0,SavedAt // get address of register save area + li k1,KSEG1_BASE // convert address of KSEG1 address + or k0,k0,k1 // + .set noat + sw AT,0(k0) // save registers AT - a3 + .set at + sw v0,4(k0) // + sw v1,8(k0) // + sw a0,12(k0) // + sw a1,16(k0) // + sw a2,20(k0) // + sw a3,24(k0) // + sw t0,28(k0) // + sw t1,32(k0) // + sw t2,36(k0) // + sw t3,40(k0) // + sw t4,44(k0) // + sw t5,48(k0) // + sw t6,52(k0) // + sw t7,56(k0) // + sw s0,60(k0) // + sw s1,64(k0) // + sw s2,68(k0) // + sw s3,72(k0) // + sw s4,76(k0) // + sw s5,80(k0) // + sw s6,84(k0) // + sw s7,88(k0) // + sw t8,92(k0) // + sw t9,96(k0) // + sw s8,100(k0) // + sw k0,104(k0) // + sw k1,108(k0) // + sw gp,112(k0) // + sw sp,116(k0) // + sw s8,120(k0) // + sw ra,124(k0) // + + mfc0 a1,cacheerr // get cache error state + nop + nop + nop + nop + nop + nop + mfc0 a0,errorepc // get error address + nop + nop + nop + nop + nop + nop + la k0,SavedErrorEpc // get address of register save area + li k1,KSEG1_BASE // convert address of KSEG1 address + or k0,k0,k1 // + sw a0,0(k0) // save errorepc register + sw a1,4(k0) // save cache error register +// +// Disable ECC and parity detection (HalpCacheFirstErr will help...) +// + + mfc0 k0,psr // get current processor state + nop + nop + nop + nop + nop + or k0,k0,0x00010000 // disable ECC and Parity detection + and k0,k0,0xfffffffe // disable interrupt + mtc0 k0,psr + and k0,k0,0xffff00e0 + mtc0 k0,psr + + +// Analysis of cacheerror register + + la k0,SavedCacheError // get address of register save area + li k1,KSEG1_BASE // convert address of KSEG1 address + or k0,k0,k1 // + lw t0,0(k0) // restore cache error register in t0 + + and t1,t0,CACHE_ERR_EE // parity error + bne t1,zero,ParityError + nop + +// +// Cache error message +// + + la a0,HalpErrCacheMsg + and a0,a0,0x1fffffff + or a0,a0,0xa0000000 + la t0,HalDisplayString + li k1,KSEG1_BASE // convert address of KSEG1 address + or t0,t0,k1 // + jal t0 // + nop + + la k0,SavedCacheError // get address of register save area + li k1,KSEG1_BASE // convert address of KSEG1 address + or k0,k0,k1 // + lw t0,0(k0) // restore cache error register in t0 + + and t1,t0,CACHE_ERR_SIDX // grab low bits of PAddr + lw t2,KiPcr + PcSecondLevelDcacheFillSize(zero) // get 2nd fill size + subu t2,t2,1 + not t2 + and t1,t2 // t1=PAddre(21..scache_block_size); SCache index +// lw t2,KiPcr + PcSecondLevelDcacheSize(zero) // get 2nd size +// subu t2,t2,1 +// and t1,t2 // t1=PAddre(21..scache_block_size); SCache index + + and t5,t0,CACHE_ERR_PIDX + sll t5,t5,0xc // align PIDX (bits 15:13) + and t2,t1,~(PIDX_PD_MASK) // suppress PIDX bits for VAddr + or t2,t5 // t2=VAddr(15..scache_block_size);PCache base index + + or t1,0x80000000 // SCache index with K0SEG address + or t2,0x80000000 // PCache base index with K0SEG address + + and t5,t0,CACHE_ERR_EC // Cache level of the error (0=primary, 1=secondary) + bne zero,t5,3f // if EC=0, Primary Cache Parity Error + nop + +1: // primary cache + + // int error + and t5,t0,CACHE_ERR_ER // data or instruction flag + bne zero,t5,2f // if ER=1 Data error + nop + + move a2,t2 + // primary cache - inst + cache INDEX_LOAD_TAG_I,0(t2) + + nop + mfc0 a3,taglo + b 5f + nop + +2: // primary cache - data + move a2,t2 + cache INDEX_LOAD_TAG_D,0(t2) + + nop + mfc0 a3,taglo + b 5f + nop + +3: // secondary cache - inst/data + move a2,t1 + cache INDEX_LOAD_TAG_SD,0(t1) + + nop + mfc0 a3,taglo +5: + +// maybe a3 will be the erroneous physical address... + + li a0,0x80 // harware error + la k0,SavedErrorEpc // get address of register save area + li k1,KSEG1_BASE // convert address of KSEG1 address + or k0,k0,k1 // + li a1,19 // restore error epc register + lw a2,4(k0) // restore cache error register + la t1,HalpKeBugCheck0 + sw a0,0(t1) + la t1,HalpKeBugCheck1 + sw a1,0(t1) + la t1,HalpKeBugCheck2 + sw a2,0(t1) + la t1,HalpKeBugCheck3 + sw a3,0(t1) + la t1,HalpKeBugCheck4 + sw zero,0(t1) + la t1,HalpBugCheckNumber + sw a1,0(t1) + la t0,KeBugCheckEx + li k1,KSEG1_BASE // convert address of KSEG1 address + or t0,t0,k1 // + jal t0 // + sw zero,0x10(sp) + lw ra,CiRa(sp) // save return address + addu sp,sp,CiFrameLength // allocate stack frame + eret + nop + +ParityError: + +// +// cacheerr contents are not usable if parity error. +// Then we must disassemble the errorepc code, get the used register +// and get the contents of this register which must cause the error. +// + +// +// Parity Error Msg +// + + la a0,HalpParityErrMsg + and a0,a0,0x1fffffff + or a0,a0,0xa0000000 + la t0,HalDisplayString + li k1,KSEG1_BASE // convert address of KSEG1 address + or t0,t0,k1 // + jal t0 // + nop + +// +// disasm +// + la k0,SavedErrorEpc // get address of register save area + li k1,KSEG1_BASE // convert address of KSEG1 address + or k0,k0,k1 // + lw a0,0(k0) + li a2,0x00 // init for one loop + move t0,a0 + +10: lw a0,0(a0) // instruction + move a1,a0 // instruction saved in a1 + li a3,HALP_OPCODE_MASK + and a0,a0,a3 + srl a0,a0,HALP_OPCODE_SHIFT + li a2,0x00 + beq a0,HALP_SWC1,8f + nop + beq a0,HALP_SDC1,8f + nop + beq a0,HALP_LWC1,8f + nop + beq a0,HALP_LDC1,8f + nop + beq a0,HALP_LB,8f + nop + beq a0,HALP_LH,8f + nop + beq a0,HALP_LW,8f + nop + beq a0,HALP_LD,8f + nop + beq a0,HALP_LBU,8f + nop + beq a0,HALP_LHU,8f + nop + beq a0,HALP_SB,8f + nop + beq a0,HALP_SH,8f + nop + beq a0,HALP_SW,8f + nop + beq a0,HALP_SD,8f + nop + beq a0,HALP_LWL,8f + nop + beq a0,HALP_LWR,8f + nop + beq a0,HALP_LDL,8f + nop + beq a0,HALP_LDR,8f + nop + beq a0,HALP_LWU,8f + nop + beq a0,HALP_SDL,8f + nop + beq a0,HALP_SDR,8f + nop + beq a0,HALP_LWU,8f + nop + beq a0,HALP_SDL,8f + nop + beq a0,HALP_SDR,8f + nop + beq a0,HALP_LL,8f + nop + beq a0,HALP_SC,8f + nop + beq a0,HALP_SCD,8f + nop + move a0,t0 + addu a0,a0,4 + beq a2,zero,10b // try the next instruction (case of branch...) + addu a2,a2,1 + + beq zero,zero,NotFoundAddr + +8: // a1 = inst en erreur + + move a2,a1 + + li a3,HALP_RT2_REG + and a2,a2,a3 + srl a3,a2,HALP_RT2_SHIFT + + subu a3,1 // reg at has 1 as number + sll a3,a3,0x2 // *4 + + la k0,SavedAt // get address of register save area + li k1,KSEG1_BASE // convert address of KSEG1 address + or k0,k0,k1 // + addu k0,k0,a3 + lw a3,0(k0) // contents of the register +// +// Try To find the physical address +// a3 = virtual address +// + + move a0,a3 + srl a0,a0,30 // two upper bits + li a2,0x2 // binary 10 + beq a0,a2,FoundAddr // KSEG0 or KSEG1 addr + nop +// mapped address => try to find it in the TLB + move a0,a3 + mfc0 t1,entryhi // get current PID and VPN2 + srl t2,a0,ENTRYHI_VPN2 // isolate VPN2 of virtual address + sll t2,t2,ENTRYHI_VPN2 // + and t1,t1,PID_MASK << ENTRYHI_PID // isolate current PID + or t2,t2,t1 // merge PID with VPN2 of virtual address + mtc0 t2,entryhi // set VPN2 and PID for probe + nop // 3 cycle hazzard + nop // + nop // + tlbp // probe for entry in TB + nop // 2 cycle hazzard + nop // + mfc0 t3,index // read result of probe + nop + bltz t3,NotFoundAddr // if ltz, entry is not in TB + sll a0,a0,0x1f - (ENTRYHI_VPN2 - 1) // shift VPN<12> into sign + tlbr // read entry from TB + nop // 3 cycle hazzard + nop // + nop // + bltz a0,11f // if ltz, check second PTE + mfc0 t2,entrylo1 // get second PTE for probe + mfc0 t2,entrylo0 // get first PTE for probe +11: mtc0 t1,entryhi // restore current PID + mtc0 zero,pagemask // restore page mask register +// t2 = entrylo + srl t2,t2,ENTRYLO_PFN + sll t2,t2,PAGE_SHIFT + li a2,PAGE_SIZE + subu a2,a2,1 + and a3,a3,a2 + or a3,a3,t2 + +FoundAddr: +// a3 = Physical addr + li a2,0x1fffffff + and a3,a3,a2 // 3 upper bits deleted + la k0,SavedErrorEpc // get address of register save area + li k1,KSEG1_BASE // convert address of KSEG1 address + or k0,k0,k1 // + lw a1,0(k0) // load error epc register + lw a2,4(k0) // load cache error register + + // compute sip num + sw a3,CiArgs0(sp) + sw a1,CiArgs1(sp) + sw a2,CiArgs2(sp) + move a0,a3 + la t0,HalpComputeNum + li k1,KSEG1_BASE // convert address of KSEG1 address + or t0,t0,k1 // + jal t0 // compute sip num + nop + lw a3,CiArgs2(sp) + sw a3,0x10(sp) + li a1,18 + lw a2,CiArgs0(sp) +ShowMsg: + li a0,0x80 + + la t1,HalpKeBugCheck0 + sw a0,0(t1) + la t1,HalpKeBugCheck1 + sw a1,0(t1) + la t1,HalpKeBugCheck2 + sw a2,0(t1) + la t1,HalpKeBugCheck3 + sw v0,0(t1) + la t1,HalpKeBugCheck4 + sw a3,0(t1) + la t1,HalpBugCheckNumber + sw a1,0(t1) + la t0,KeBugCheckEx + li k1,KSEG1_BASE // convert address of KSEG1 address + or t0,t0,k1 // + jal t0 // + move a3,v0 // sip num + + lw ra,CiRa(sp) // save return address + addu sp,sp,CiFrameLength // allocate stack frame + eret // + +NotFoundAddr: + + la a0,HalpAddrErrMsg + and a0,a0,0x1fffffff + or a0,a0,0xa0000000 + la t0,HalDisplayString + li k1,KSEG1_BASE // convert address of KSEG1 address + or t0,t0,k1 // + jal t0 // + nop + + move a3,a1 + li a0,0x80 + la k0,SavedErrorEpc // get address of register save area + li k1,KSEG1_BASE // convert address of KSEG1 address + or k0,k0,k1 // + li a1,18 + li a2,0x00 + lw a3,4(k0) + sw a3,0x10(sp) + la t1,HalpKeBugCheck0 + sw a0,0(t1) + la t1,HalpKeBugCheck1 + sw a1,0(t1) + la t1,HalpKeBugCheck2 + sw a2,0(t1) + la t1,HalpKeBugCheck3 + sw v0,0(t1) + la t1,HalpKeBugCheck4 + sw a3,0(t1) + la t1,HalpBugCheckNumber + sw a1,0(t1) + la t0,KeBugCheckEx + li k1,KSEG1_BASE // convert address of KSEG1 address + or t0,t0,k1 // + jal t0 // + li a3,0xff + + lw ra,CiRa(sp) // save return address + addu sp,sp,CiFrameLength // allocate stack frame + eret // + + .set reorder + + .end HalpCacheErrorRoutine diff --git a/private/ntos/nthals/halsnip/mips/duocache.s b/private/ntos/nthals/halsnip/mips/duocache.s new file mode 100644 index 000000000..8d743a0b5 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/duocache.s @@ -0,0 +1,780 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/duocache.s,v 1.4 1996/02/23 17:55:12 pierre Exp $") +// TITLE("Cache Flush") +//++ +// +// Copyright (c) 1991-1993 Microsoft Corporation +// +// Module Name: +// +// duocache.s +// +// Abstract: +// +// This module implements the code necessary for cache operations on +// MIPS R4000 MultiProcerssor Machines. It is very special to SNI machines, +// which use a special MP Agent Asic. +//` +// Environment: +// +// Kernel mode only. +// +//-- + +#include "halmips.h" +#include "SNIdef.h" + +// NON COHERENT algorithm : to use the replace facility of the MP_Agent + +#define CONFIG_NONCOH(reg) \ + .set noreorder; \ + .set noat; \ + mfc0 reg,config; \ + nop; \ + nop; \ + and AT,reg,~(7); \ + or AT,AT,0x3; \ + mtc0 AT,config; \ + nop; \ + nop; \ + nop; \ + nop; \ + .set at; \ + .set reorder + +// restauration of CONFIG register + +#define CONFIG_RESTORE(reg) \ + .set noreorder; \ + mtc0 reg,config; \ + nop; \ + nop; \ + nop; \ + nop; \ + .set reorder + +// beql : if the cond branch is not taken, the inst in the delay-slot is nullified + +#define LOAD_RPL_ADDR(reg,reg1) \ + lw reg,HalpMpaCacheReplace; \ +2: + + + +// +// Define cache operations constants. +// + +#define COLOR_BITS (7 << PAGE_SHIFT) // color bit (R4000 - 8kb cache) +#define COLOR_MASK (0x7fff) // color mask (R4000 - 8kb cache) +#define FLUSH_BASE 0xfffe0000 // flush base address +#define PROTECTION_BITS ((1 << ENTRYLO_V) | (1 << ENTRYLO_D) ) // + + SBTTL("Processor Identification") +//++ +// +// VOID +// HalpProcIdentify() +// +// Routine Description: +// +// This function reads the implementation number in the prid register. +// +// Arguments: +// +// None +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpProcIdentify) + + .set noreorder + .set noat + mfc0 v0,prid + nop + srl v0,PRID_IMP + and v0,0xff + j ra + nop + + .end HalpProcIdentify + + SBTTL("Flush Data Cache Page") +//++ +// +// VOID +// HalpFlushDcachePageMulti ( +// IN PVOID Color, +// IN ULONG PageFrame, +// IN ULONG Length +// ) +// +// Routine Description: +// +// This function flushes (hit/writeback/invalidate) up to a page of data +// from the data cache. +// +// Arguments: +// +// Color (a0) - Supplies the starting virtual address and color of the +// data that is flushed. +// +// PageFrame (a1) - Supplies the page frame number of the page that +// is flushed. +// +// Length (a2) - Supplies the length of the region in the page that is +// flushed. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpFlushDcachePageMulti) + +#if DBG + + lw t0,KeDcacheFlushCount // get address of dcache flush count + lw t1,0(t0) // increment the count of flushes + addu t1,t1,1 // + sw t1,0(t0) // store result +#endif + +15: DISABLE_INTERRUPTS(t5) // disable interrupts + + .set noreorder + .set noat + +// +// Flush the primary and secondary data caches. +// + +// +// HIT_WRITEBACK_INVALIDATE cache instruction does not update the SC +// TagRam copy in the MP Agent. So we do cache replace. +// + + .set noreorder + .set noat +40: and a0,a0,PAGE_SIZE -1 // PageOffset + sll t7,a1,PAGE_SHIFT // physical address + lw t4,KiPcr + PcSecondLevelDcacheFillSize(zero) // get 2nd fill size + or t0,t7,a0 // physical address + offset + subu t6,t4,1 // compute block size minus one + and t7,t0,t6 // compute offset in block + addu a2,a2,t6 // round up to next block + addu a2,a2,t7 // + nor t6,t6,zero // complement block size minus one + and a2,a2,t6 // truncate length to even number + beq zero,a2,60f // if eq, no blocks to flush + and t8,t0,t6 // compute starting virtual address + addu t9,t8,a2 // compute ending virtual address + subu t9,t9,t4 // compute ending loop address + + LOAD_RPL_ADDR(a3,a2) // get base flush address + lw t0,KiPcr + PcSecondLevelDcacheSize(zero) // get cache size + add t0,t0,-1 // mask of the cache size + CONFIG_NONCOH(t2) // NON COHERENT algorithm + .set noreorder + .set noat + +50: and t7,t8,t0 // offset + addu t7,t7,a3 // physical address + offset + lw zero,0(t7) // load Cache -> Write back old Data + bne t8,t9,50b // if ne, more blocks to invalidate + addu t8,t8,t4 // compute next block address (+Linesize) + + CONFIG_RESTORE(t2) + +60: ENABLE_INTERRUPTS(t5) // enable interrupts + + j ra // return + + .end HalpFlushDcachePageMulti + + + SBTTL("Purge Instruction Cache Page") +//++ +// +// VOID +// HalpPurgeIcachePageMulti ( +// IN PVOID Color, +// IN ULONG PageFrame, +// IN ULONG Length +// ) +// +// Routine Description: +// +// This function purges (hit/invalidate) up to a page of data from the +// instruction cache. +// +// Arguments: +// +// Color (a0) - Supplies the starting virtual address and color of the +// data that is purged. +// +// PageFrame (a1) - Supplies the page frame number of the page that +// is purged. +// +// Length (a2) - Supplies the length of the region in the page that is +// purged. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpPurgeIcachePageMulti) + +#if DBG + + lw t0,KeIcacheFlushCount // get address of icache flush count + lw t1,0(t0) // increment the count of flushes + addu t1,t1,1 // + sw t1,0(t0) // store result + +#endif + + .set noreorder + .set noat + lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache policy + and a0,a0,COLOR_MASK // isolate color bits + li t0,FLUSH_BASE // get base flush address + or t0,t0,a0 // compute color virtual address + sll t1,a1,ENTRYLO_PFN // shift page frame into position + or t1,t1,PROTECTION_BITS // merge protection bits + or t1,t1,v0 // merge cache policy + and a0,a0,0x1000 // isolate TB entry index + beql zero,a0,10f // if eq, first entry + move t2,zero // set second page table entry + move t2,t1 // set second page table entry + move t1,zero // set first page table entry +10: mfc0 t3,wired // get TB entry index + lw t4,KiPcr + PcSecondLevelIcacheFillSize(zero) // get 2nd fill size + .set at + .set reorder + +// +// Purge data from the instruction cache. +// + +15: DISABLE_INTERRUPTS(t5) // disable interrupts + + .set noreorder + .set noat + mfc0 t6,entryhi // get current PID and VPN2 + srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address + sll t7,t7,ENTRYHI_VPN2 // + and t6,t6,0xff << ENTRYHI_PID // isolate current PID + or t7,t7,t6 // merge PID with VPN2 of virtual address + mtc0 t7,entryhi // set VPN2 and PID for probe + mtc0 t1,entrylo0 // set first PTE value + mtc0 t2,entrylo1 // set second PTE value + mtc0 t3,index // set TB index value + nop // fill + tlbwi // write TB entry - 3 cycle hazzard + subu t6,t4,1 // compute block size minus one + and t7,t0,t6 // compute offset in block + addu a2,a2,t6 // round up to next block + addu a2,a2,t7 // + nor t6,t6,zero // complement block size minus one + and a2,a2,t6 // truncate length to even number + beq zero,a2,60f // if eq, no blocks to purge + and t8,t0,t6 // compute starting virtual address + addu t9,t8,a2 // compute ending virtual address + subu t9,t9,t4 // compute ending loop address + +// +// Purge the primary and secondary instruction caches. +// + .set noreorder + .set noat + +40: move t7,t8 + +// +// HIT_WRITEBACK_INVALIDATE cache instruction does not work. So we do cache replace. +// We use a MP agent facility to do that : a 4Mb area is stolen to the upper EISA space +// and this address is notified to the MP agent. When the cache replace is done, no +// access to the memory is done : the MP agent returns zero as value for these addresses. +// Be careful : to use this mechanism, CONFIG register must be programmed in NON COHERENT +// mode, so we must be protected from interrupts. +// + + li t8,PAGE_SIZE + add t8,t8,-1 // page mask + and t8,t7,t8 // offset in the page + sll t7,a1,PAGE_SHIFT // physical address + or t8,t7,t8 // physical address + offset + +// +// note: we have a Unified SLC, so SecondLevelIcacheSize is set to 0 +// + + lw t0,KiPcr + PcSecondLevelIcacheSize(zero) // get cache size + + addu t9,t8,a2 // compute ending physical address + subu t9,t9,t4 // compute ending loop address + + add t0,t0,-1 // mask of the cache size + and t8,t8,t0 // first cache line to invalidate + and t9,t9,t0 // last cache line to invalidate + + LOAD_RPL_ADDR(a2,a3) + + or t8,a2,t8 // starting address + or t9,a2,t9 // ending address + CONFIG_NONCOH(t2) // NON COHERENT algorithm + .set noreorder + .set noat + +50: lw zero,0(t8) // invalidate sc + bne t8,t9,50b // if ne, more blocks to invalidate + addu t8,t8,t4 // compute next block address + + CONFIG_RESTORE(t2) + +60: ENABLE_INTERRUPTS(t5) // enable interrupts + + j ra // return + + .end HalPurgeIcachePage + + + SBTTL("Sweep Data Cache") +//++ +// +// VOID +// HalpSweepDcacheMulti ( +// VOID +// ) +// +// Routine Description: +// +// This function sweeps (index/writeback/invalidate) the entire data cache. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpSweepDcacheMulti) + +#if DBG + + lw t0,KeDcacheFlushCount // get address of dcache flush count + lw t1,0(t0) // increment the count of flushes + addu t1,t1,1 // + sw t1,0(t0) // store result +#endif + + .set at + .set reorder + + DISABLE_INTERRUPTS(t3) // disable interrupts + + .set noreorder + .set noat + +// +// sweep secondary cache in the MP Agent +// + +// +// HIT_WRITEBACK_INVALIDATE cache instruction does not update the SC +// TagRam copy in the MP Agent. So we do cache replace. +// + + lw t0,KiPcr + PcSecondLevelDcacheSize(zero) // get data cache size + lw t1,KiPcr + PcSecondLevelDcacheFillSize(zero) // get block size + + LOAD_RPL_ADDR(a0,t5) // starting address + addu a1,a0,t0 // compute ending cache address + subu a1,a1,t1 // compute ending block address + + CONFIG_NONCOH(t2) // NON COHERENT algorithm + + .set noreorder + .set noat + +25: + lw zero,0(a0) + bne a0,a1,25b // if ne, more to invalidate + addu a0,a0,t1 // compute address of next block + + CONFIG_RESTORE(t2) + + ENABLE_INTERRUPTS(t3) // enable interrupts + + .set at + .set reorder + + j ra // return + + + .end HalpSweepDcacheMulti + + + SBTTL("Sweep Instruction Cache") +//++ +// +// VOID +// HalpSweepIcacheMulti ( +// VOID +// ) +// +// Routine Description: +// +// This function sweeps (index/invalidate) the entire instruction cache. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpSweepIcacheMulti) + +#if DBG + + lw t0,KeIcacheFlushCount // get address of icache flush count + lw t1,0(t0) // increment the count of flushes + addu t1,t1,1 // + sw t1,0(t0) // store result +#endif +// +// Sweep the secondary instruction cache. +// + + .set noreorder + .set noat + + DISABLE_INTERRUPTS(t3) // disable interrupts + .set noreorder + .set noat + +// +// sweep secondary cache +// SNI machines have only an Unified SL cache +// NOTE: PcSecondLevelIcacheSize and PcSecondLevelICacheFillSize is set to 0 +// on SNI machines +// + + lw t0,KiPcr + PcSecondLevelIcacheSize(zero) // get instruction cache size + lw t1,KiPcr + PcSecondLevelIcacheFillSize(zero) // get fill size + LOAD_RPL_ADDR(a0,a3) // set starting index value + addu a1,a0,t0 // compute ending cache address + subu a1,a1,t1 // compute ending block address + + CONFIG_NONCOH(t2) // NON COHERENT algorithm + .set noreorder + .set noat + +10: lw zero,0(a0) + bne a0,a1,10b // if ne, more to invalidate + addu a0,a0,t1 // compute address of next block + + CONFIG_RESTORE(t2) + .set noreorder + .set noat + + +20: lw t0,KiPcr + PcFirstLevelIcacheSize(zero) // get instruction cache size + lw t1,KiPcr + PcFirstLevelIcacheFillSize(zero) // get fill size + li a0,KSEG0_BASE // set starting index value + addu a1,a0,t0 // compute ending cache address + subu a1,a1,t1 // compute ending block address + +// +// Sweep the primary instruction cache. +// + +30: cache INDEX_INVALIDATE_I,0(a0) // invalidate cache line + bne a0,a1,30b // if ne, more to invalidate + addu a0,a0,t1 // compute address of next block + ENABLE_INTERRUPTS(t3) // enable interrupts + + .set at + .set reorder + j ra // return + + .end HalSweepIcache + + + SBTTL("Zero Page") +//++ +// +// VOID +// HalpZeroPageMulti ( +// IN PVOID NewColor, +// IN PVOID OldColor, +// IN ULONG PageFrame +// ) +// +// Routine Description: +// +// This function zeros a page of memory. +// +// The algorithm used to zero a page is as follows: +// +// 1. Purge (hit/invalidate) the page from the instruction cache +// using the old color iff the old color is not the same as +// the new color. +// +// 2. Purge (hit/invalidate) the page from the data cache using +// the old color iff the old color is not the same as the new +// color. +// +// 3. Create (create/dirty/exclusive) the page in the data cache +// using the new color. +// +// 4. Write zeros to the page using the new color. +// +// Arguments: +// +// NewColor (a0) - Supplies the page aligned virtual address of the +// new color of the page that is zeroed. +// +// OldColor (a1) - Supplies the page aligned virtual address of the +// old color of the page that is zeroed. +// +// PageFrame (a2) - Supplies the page frame number of the page that +// is zeroed. +// +// Return Value: +// +// None. +// +//-- + + .struct 0 + .space 3 * 4 // fill +ZpRa: .space 4 // saved return address +ZpFrameLength: // length of stack frame +ZpA0: .space 4 // (a0) +ZpA1: .space 4 // (a1) +ZpA2: .space 4 // (a2) +ZpA3: .space 4 // (a3) + + NESTED_ENTRY(HalpZeroPageMulti, ZpFrameLength, zero) + + subu sp,sp,ZpFrameLength // allocate stack frame + sw ra,ZpRa(sp) // save return address + + PROLOGUE_END + + and a0,a0,COLOR_BITS // isolate new color bits + and a1,a1,COLOR_BITS // isolate old color bits + sw a0,ZpA0(sp) // save new color bits + sw a1,ZpA1(sp) // save old color bits + sw a2,ZpA2(sp) // save page frame + +// +// If the old page color is not equal to the new page color, then change +// the color of the page. +// + + beq a0,a1,10f // if eq, colors match + jal KeChangeColorPage // chagne page color + +// +// Create dirty exclusive cache blocks and zero the data. +// + +10: lw a3,ZpA0(sp) // get new color bits + lw a1,ZpA2(sp) // get page frame number + + .set noreorder + .set noat + lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache polciy + li t0,FLUSH_BASE // get base flush address + or t0,t0,a3 // compute new color virtual address + sll t1,a1,ENTRYLO_PFN // shift page frame into position + or t1,t1,PROTECTION_BITS // merge protection bits + or t1,t1,v0 // merge cache policy + and a3,a3,0x1000 // isolate TB entry index + beql zero,a3,20f // if eq, first entry + move t2,zero // set second page table entry + move t2,t1 // set second page table entry + move t1,zero // set first page table entry +20: mfc0 t3,wired // get TB entry index + lw t4,KiPcr + PcFirstLevelDcacheFillSize(zero) // get 1st fill size + lw v0,KiPcr + PcSecondLevelDcacheFillSize(zero) // get 2nd fill size + .set at + .set reorder + + DISABLE_INTERRUPTS(t5) // disable interrupts + + .set noreorder + .set noat + mfc0 t6,entryhi // get current PID and VPN2 + srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address + sll t7,t7,ENTRYHI_VPN2 // + and t6,t6,0xff << ENTRYHI_PID // isolate current PID + or t7,t7,t6 // merge PID with VPN2 of virtual address + mtc0 t7,entryhi // set VPN2 and PID for probe + mtc0 t1,entrylo0 // set first PTE value + mtc0 t2,entrylo1 // set second PTE value + mtc0 t3,index // set TB index value + nop // fill + tlbwi // write TB entry - 3 cycle hazzard + addu t9,t0,PAGE_SIZE // compute ending address of block + dmtc1 zero,f0 // set write pattern + and t8,t4,0x10 // test if 16-byte cache block + +// +// Zero page in primary and secondary data caches. +// + +50: sdc1 f0,0(t0) // zero 64-byte block + sdc1 f0,8(t0) // + sdc1 f0,16(t0) // + sdc1 f0,24(t0) // + sdc1 f0,32(t0) // + sdc1 f0,40(t0) // + sdc1 f0,48(t0) // + addu t0,t0,64 // advance to next 64-byte block + bne t0,t9,50b // if ne, more to zero + sdc1 f0,-8(t0) // + + .set at + .set reorder + + ENABLE_INTERRUPTS(t5) // enable interrupts + + lw ra,ZpRa(sp) // get return address + addu sp,sp,ZpFrameLength // deallocate stack frame + j ra // return + + .end HalpZeroPageMulti + + + SBTTL("Zero Page") +//++ +// +// VOID +// HalpMultiPciEccCorrector ( +// IN PVOID PhysicalAddr, +// IN PVOID PageFrame, +// IN ULONG Length +// ) +// +// Routine Description: +// +// This function corrects an ECC. +// +// +// Arguments: +// +// a0 : virtual +// a1 : pfn +// a2 : length +// +// Return Value: +// +// None. +// +//-- + + + LEAF_ENTRY(HalpMultiPciEccCorrector) + +// +// to avoid Virtual Coherency Exception (unrecoverable with NT) +// flush of the primary cache. So the physical address won't +// be twice in the primary cache. +// + DISABLE_INTERRUPTS(t5) // disable interrupts + + .set noreorder + .set noat +// +// first, we make a virtual address to get the corrected address in the cache +// secondly, we flush it by cache replace mechanism +// + + and a0,a0,COLOR_MASK // isolate color and offset bits + lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache policy + li t0,FLUSH_BASE // get base flush address + or t0,t0,a0 // compute color virtual address + sll t1,a1,ENTRYLO_PFN // shift page frame into position + or t1,t1,PROTECTION_BITS // merge protection bits + or t1,t1,v0 // merge cache policy + and a0,a0,0x1000 // isolate TB entry index + beql zero,a0,10f // if eq, first entry + move t2,zero // set second page table entry + move t2,t1 // set second page table entry + move t1,zero // set first page table entry +10: mfc0 t3,wired // get TB entry index + lw v0,KiPcr + PcSecondLevelDcacheFillSize(zero) // get 2nd fill size + lw t4,KiPcr + PcFirstLevelDcacheFillSize(zero) // get 1st fill size + bnel zero,v0,15f // if ne, second level cache present + move t4,v0 // set flush block size + +15: mfc0 t6,entryhi // get current PID and VPN2 + srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address + sll t7,t7,ENTRYHI_VPN2 // + and t6,t6,0xff << ENTRYHI_PID // isolate current PID + or t7,t7,t6 // merge PID with VPN2 of virtual address + mtc0 t7,entryhi // set VPN2 and PID for probe + mtc0 t1,entrylo0 // set first PTE value + mtc0 t2,entrylo1 // set second PTE value + mtc0 t3,index // set TB index value + nop // fill + tlbwi // write TB entry - 3 cycle hazzard + + subu t6,t4,1 // compute block size minus one + and t7,t0,t6 // compute offset in block + addu a2,a2,t6 // round up to next block + addu a2,a2,t7 // + nor t6,t6,zero // complement block size minus one + and a2,a2,t6 // truncate length to even number + and t8,t0,t6 // compute starting virtual address + addu t9,t8,a2 // compute ending virtual address + subu t9,t9,t4 // compute ending loop address + +// +// load data and flush it to correct the ECC +// + + LOAD_RPL_ADDR(a3,a2) // get base flush address + lw t0,KiPcr + PcSecondLevelDcacheSize(zero) // get cache size + add t0,t0,-1 // mask of the cache size + .set noreorder + .set noat + +50: lw t7,0(t8) + sw t7,0(t8) + + and t7,t8,t0 // offset + addu t7,t7,a3 // physical address + offset + CONFIG_NONCOH(t2) // NON COHERENT algorithm + lw zero,0(t7) // load Cache -> Write back old Data + CONFIG_RESTORE(t2) + + lw t7,0(t8) // t8 fffe0400 et entree tlb ->417 =>ok + + bne t8,t9,50b // if ne, more blocks to invalidate + addu t8,t8,t4 // compute next block address (+Linesize) + +60: + ENABLE_INTERRUPTS(t5) // enable interrupts + + j ra // return + + + .end HalpMultiPciEccCorrector diff --git a/private/ntos/nthals/halsnip/mips/halp.h b/private/ntos/nthals/halsnip/mips/halp.h new file mode 100644 index 000000000..d6edc0499 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/halp.h @@ -0,0 +1,280 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/halp.h,v 1.4 1996/02/23 17:55:12 pierre Exp $") +/*++ + +Copyright (c) 1991-1993 Microsoft Corporation + +Module Name: + + halp.h + +Abstract: + + This header file defines the private Hardware Architecture Layer (HAL) + interfaces. + + +--*/ + +#ifndef _HALP_ +#define _HALP_ + +#if defined(NT_UP) + +#undef NT_UP + +#endif + +#include "nthal.h" +#include "hal.h" +#include "SNIhalp.h" +#include "xm86.h" +#include "x86new.h" + + +extern ULONG HalpKeBugCheck0; +extern ULONG HalpKeBugCheck1; +extern ULONG HalpKeBugCheck2; +extern ULONG HalpKeBugCheck3; +extern ULONG HalpKeBugCheck4; + +#define HalpKeBugCheckEx(p0,p1,p2,p3,p4) \ + {\ + HalpKeBugCheck0 = p0;\ + HalpKeBugCheck1 = p1;\ + HalpKeBugCheck2 = p2;\ + HalpKeBugCheck3 = p3;\ + HalpKeBugCheck4 = p4;\ + KeBugCheckEx(p0,p1,p2,p3,p4); \ + }\ + + +typedef struct _HALP_BUGCHECK_BUFFER { + ULONG Par0; + ULONG Par1; + ULONG Par2; + ULONG Par3; + ULONG Par4; + ULONG MainBoard; + UCHAR TEXT[50]; +} HALP_BUGCHECK_BUFFER, *PHALP_BUGCHECK_BUFFER; + +// +// Define function prototypes. +// + +ULONG +HalpAllocateTbEntry ( + VOID + ); + +VOID +HalpFreeTbEntry ( + VOID + ); + +VOID +HalpCacheErrorRoutine ( + VOID + ); + +BOOLEAN +HalpCalibrateStall ( + VOID + ); + +VOID +HalpClockInterrupt( + VOID + ); + + +VOID +HalpClockInterruptPciTower( + VOID + ); + +VOID +HalpClockInterrupt1( + VOID + ); + +BOOLEAN +HalpInitializeDisplay0( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ); + +BOOLEAN +HalpInitializeDisplay1( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ); + +BOOLEAN +HalpInitializeInterrupts ( + VOID + ); + +VOID +HalpProfileInterrupt ( + VOID + ); + +ULONG +HalpReadCountRegister ( + VOID + ); + +ULONG +HalpWriteCompareRegisterAndClear ( + IN ULONG Value + ); + + +VOID +HalpStallInterrupt ( + VOID + ); + +VOID +HalpResetX86DisplayAdapter( + VOID + ); + +VOID +HalpSendIpi( + IN ULONG pcpumask, + IN ULONG msg_data + ); + +VOID +HalpRequestIpi( + IN ULONG pcpumask, + IN ULONG msg_data + ); + +VOID +HalpProcessIpi ( + IN struct _KTRAP_FRAME *TrapFrame + ); + +VOID +HalpInitMPAgent ( + IN ULONG Number + ); + +ULONG +HalpGetMyAgent( + VOID + ); + +BOOLEAN +HalpCheckSpuriousInt( + ULONG mask + ); + +VOID +HalpBootCpuRestart( + VOID + ); + +ULONG +HalpGetPCIData ( + IN ULONG BusNumber, + IN ULONG Slot, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +ULONG +HalpSetPCIData ( + IN ULONG BusNumber, + IN ULONG Slot, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ) ; + + +NTSTATUS +HalpAssignPCISlotResources ( + IN ULONG BusNumber, + IN PUNICODE_STRING RegistryPath, + IN PUNICODE_STRING DriverClassName OPTIONAL, + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT DeviceObject OPTIONAL, + IN ULONG Slot, + IN OUT PCM_RESOURCE_LIST *pAllocatedResources + ); + +NTSTATUS +HalpAdjustPCIResourceList ( + IN ULONG BusNumber, + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList + ); + +VOID +HalpInit2MPAgent( + VOID + ); + +VOID +HalpInitMAUIMPAgent( + VOID + ); + +BOOLEAN +HalpCreateIntPciMAUIStructures( + CCHAR Number + ); + +VOID +HalpBugCheckCallback ( + IN PVOID Buffer, + IN ULONG Length + ); + +ULONG +HalpFindEccAddr( + ULONG Addr, // from ECC Error Asic Register + PVOID ErrStatusRegister, // register which indicates parity and Ecc error + PVOID ErrStatusBits // bits which indicates errors in the previous register + ); + +USHORT +HalpComputeNum( + UCHAR *PhysAddr + ); + +// +// Define external references. +// + +extern HALP_BUGCHECK_BUFFER HalpBugCheckBuffer; + +extern KBUGCHECK_CALLBACK_RECORD HalpCallbackRecord; + +extern UCHAR HalpComponentId[]; + +extern ULONG HalpBugCheckNumber; + +extern PUCHAR HalpBugCheckMessage[]; +extern ULONG HalpColumn; +extern ULONG HalpRow; +extern KINTERRUPT HalpInt3Interrupt; // Interrupt Object for IT3 tower multipro +extern ULONG HalpCurrentTimeIncrement; +extern ULONG HalpNextTimeIncrement; +extern ULONG HalpNewTimeIncrement; +extern KSPIN_LOCK HalpBeepLock; +extern KSPIN_LOCK HalpDisplayAdapterLock; +extern KSPIN_LOCK HalpSystemInterruptLock; +extern KSPIN_LOCK HalpInterruptLock; +extern KSPIN_LOCK HalpMemoryBufferLock; +extern ULONG HalpProfileCountRate; +extern ULONG HalpStallScaleFactor; +extern PULONG HalpPciConfigAddr; +extern PULONG HalpPciConfigData; +extern UCHAR HalpIntAMax; +extern UCHAR HalpIntBMax; +extern UCHAR HalpIntCMax; +extern UCHAR HalpIntDMax; +#endif // _HALP_ diff --git a/private/ntos/nthals/halsnip/mips/i82c54.h b/private/ntos/nthals/halsnip/mips/i82c54.h new file mode 100644 index 000000000..3eb213052 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/i82c54.h @@ -0,0 +1,34 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/i82c54.h,v 1.1 1995/07/20 15:55:16 flo Exp $") +/*++ + +Copyright (c) 1993-1994 Siemens Nixdorf Informationssysteme AG + +Module Name: + + i82C54.h + +Abstract: + + This header file defines the private Address structure for + the Intel 82C54 Timer chip found on the SNI Minitower and RM400-10. + + +--*/ + +#ifndef _I82C54_ +#define _I82C54_ +// +// the SNI Clock (i82C54) Structure +// + +typedef struct _LOCAL_8254 { + UCHAR counter0; /* counter 0 port */ + char fill_1[3]; + UCHAR counter1; /* counter 1 port */ + char fill_2[3]; + UCHAR counter2; /* counter 2 port */ + char fill_3[3]; + UCHAR control; /* control word */ +} LOCAL_8254, *PLOCAL_8254; + +#endif diff --git a/private/ntos/nthals/halsnip/mips/j4flshbf.s b/private/ntos/nthals/halsnip/mips/j4flshbf.s new file mode 100644 index 000000000..a4ce6e784 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/j4flshbf.s @@ -0,0 +1,53 @@ +#if defined(R4000) +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/j4flshbf.s,v 1.1 1995/07/20 15:56:14 flo Exp $") + +// TITLE("Miscellaneous Kernel Functions") +//++ +// +// Copyright (c) 1991-1993 Microsoft Corporation +// +// Module Name: +// +// j4flshbf.s +// +// Abstract: +// +// This module implements the system dependent kernel function to flush +// the write buffer or otherwise synchronize writes on a MIPS R4000 Jazz +// system. +// +//-- + +#include "halmips.h" + + SBTTL("Flush Write Buffer") +//++ +// +// NTSTATUS +// KeFlushWriteBuffer ( +// VOID +// ) +// +// Routine Description: +// +// This function flushes the write buffer on the current processor. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(KeFlushWriteBuffer) + + sync // synchronize writes + j ra // return + + .end KeFlushWritebuffer + + +#endif diff --git a/private/ntos/nthals/halsnip/mips/j4flshio.c b/private/ntos/nthals/halsnip/mips/j4flshio.c new file mode 100644 index 000000000..7a785169a --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/j4flshio.c @@ -0,0 +1,199 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/j4flshio.c,v 1.3 1996/03/04 13:14:32 pierre Exp $") + + +/*++ + +Copyright (c) 1991-1993 Microsoft Corporation + +Module Name: + + j4flshio.c + +Abstract: + + + This module implements the system dependent kernel function to flush + the data cache for I/O transfers on a SNI MIPS R4x00 machine. + + +--*/ + +#include "halp.h" + + +VOID +HalFlushIoBuffers ( + IN PMDL Mdl, + IN BOOLEAN ReadOperation, + IN BOOLEAN DmaOperation + ) + +/*++ + +Routine Description: + + This function flushes the I/O buffer specified by the memory descriptor + list from the data cache on the current processor. + +Arguments: + + Mdl - Supplies a pointer to a memory descriptor list that describes the + I/O buffer location. + + ReadOperation - Supplies a boolean value that determines whether the I/O + operation is a read into memory. + + DmaOperation - Supplies a boolean value that determines whether the I/O + operation is a DMA operation. + +Return Value: + + None. + +--*/ + +{ + + ULONG CacheSegment; + ULONG Length; + ULONG Offset; + PULONG PageFrame; + ULONG Source; + + // + // The SNI MIPS R4x00 machines use a write back data cache and, therefore, must be + // flushed on reads and writes. + // + // If the length of the I/O operation is greater than the size of the + // data cache, then sweep the entire data cache. Otherwise, flush + // individual pages from the data cache as appropriate. + // + + Offset = Mdl->ByteOffset & PCR->DcacheAlignment; + Length = (Mdl->ByteCount + + PCR->DcacheAlignment + Offset) & ~PCR->DcacheAlignment; + + if ((Length > PCR->FirstLevelDcacheSize) && + (Length > PCR->SecondLevelDcacheSize)) { + + // + // If the I/O operation is a DMA operation, or the I/O operation is + // not a DMA operation and the I/O operation is a page read operation, + // then sweep (index/writeback/invalidate) the entire data cache. + // + + if ((DmaOperation != FALSE) || + ((DmaOperation == FALSE) && + (ReadOperation != FALSE) && + ((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0))) { + HalSweepDcache(); + } + + // + // If the I/O operation is a page read, then sweep (index/invalidate) + // the entire instruction cache. + // + + if ((ReadOperation != FALSE) && + ((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0)) { + HalSweepIcache(); + } + + } else { + + // + // Flush or purge the specified pages from the data cache and + // instruction caches as appropriate. + // + // Compute the number of pages to flush and the starting MDL page + // frame address. + // + + Offset = Mdl->ByteOffset & ~PCR->DcacheAlignment; + PageFrame = (PULONG)(Mdl + 1); + Source = ((ULONG)(Mdl->StartVa) & 0xfffff000) | Offset; + + // + // Flush or purge the specified page segments from the data and + // instruction caches as appropriate. + // + + do { + if (Length >= (PAGE_SIZE - Offset)) { + CacheSegment = PAGE_SIZE - Offset; + + } else { + CacheSegment = Length; + } + + if (ReadOperation == FALSE) { + + // + // The I/O operation is a write and the data only needs to + // to be copied back into memory if the operation is also + // a DMA operation. + // + + if (DmaOperation != FALSE) { + HalFlushDcachePage((PVOID)Source, *PageFrame, CacheSegment); + } + + } else { + + // + // If the I/O operation is a DMA read or a page read + // operation, then flush the data cache. + // + if (DmaOperation != FALSE) { + HalFlushDcachePage((PVOID)Source, *PageFrame, CacheSegment); + + } else if ((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0) { + HalFlushDcachePage((PVOID)Source, *PageFrame, CacheSegment); + } + + // + // If the I/O operation is a page read, then the instruction + // cache must be purged. + // + + if ((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0) { + HalPurgeIcachePage((PVOID)Source, *PageFrame, CacheSegment); + } + } + + PageFrame += 1; + Length -= CacheSegment; + Offset = 0; + Source += CacheSegment; + } while(Length != 0); + } + + return; +} + +ULONG +HalGetDmaAlignmentRequirement ( + VOID + ) + +/*++ + +Routine Description: + + This function returns the alignment requirements for DMA transfers on + host system. + +Arguments: + + None. + +Return Value: + + The DMA alignment requirement is returned as the fucntion value. + +--*/ + +{ + + return PCR->DcacheFillSize; +} diff --git a/private/ntos/nthals/halsnip/mips/j4prof.c b/private/ntos/nthals/halsnip/mips/j4prof.c new file mode 100644 index 000000000..7b360f1cc --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/j4prof.c @@ -0,0 +1,316 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + j4prof.c + +Abstract: + + This module contains the code to start and stop the profiling interrupt + and to compute the profiling interval for a MIPS R4000 Jazz system. + +Author: + + David N. Cutler (davec) 21-Feb-1991 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +// #include "ki.h" +#include "halp.h" + +// +// Define one second and round values. +// + +#define ONE_SECOND (10 * 1000 * 1000) // 1 second in 100ns units +#define ROUND_VALUE ((ONE_SECOND) - 1) // 1 second minus 100ns + +// +// Define static data. +// + +LARGE_INTEGER HalpPerformanceCounter[8]; +ULONG HalpProfileInterval = DEFAULT_PROFILE_INTERVAL; + +LARGE_INTEGER +KeQueryPerformanceCounter ( + OUT PLARGE_INTEGER Frequency OPTIONAL + ) + +/*++ + +Routine Description: + + This routine returns the current performance counter value and the + performance counter frequency. + +Arguments: + + Frequency - Supplies an optional pointer to a variable which receives + the performance counter frequency in Hertz. + +Return Value: + + The current performance counter value is returned as the function + value. + +--*/ + +{ + + ULONG CurrentCount; + KIRQL OldIrql; + LARGE_INTEGER PerformanceCounter; + + // + // Raise IRQL to PROFILE_LEVEL, read the current value of the count + // register, read the performance counter, and lower IRQL to its + // previous value. + // + // N.B. The minimum, maximum, and default values for the profile + // count are chosen such that count register only overflows + // after about 20 seconds at 50mhz. Therefore, there is never + // a problem with the counter wrapping in the following code. + // + + KeRaiseIrql(PROFILE_LEVEL, &OldIrql); + CurrentCount = HalpReadCountRegister(); + PerformanceCounter = HalpPerformanceCounter[KeGetCurrentPrcb()->Number]; + KeLowerIrql(OldIrql); + + // + // If the frequency parameter is specified, then return the performance + // counter frequency as the current system time frequency. + // + + if (ARGUMENT_PRESENT(Frequency) != FALSE) { + Frequency->QuadPart = HalpProfileCountRate; + } + + // + // Return the value of the performance counter. + // + + PerformanceCounter.QuadPart += CurrentCount; + return PerformanceCounter; +} + +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. + +--*/ + +{ + + KIRQL OldIrql; + PKPRCB Prcb; + + // + // Raise IRQL to HIGH_LEVEL, decrement the number of processors, and + // wait until the number is zero. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + if (InterlockedDecrement(Number) != RESULT_ZERO) { + do { + } while (*Number !=0); + } + + // + // Write the compare register, clear the count register, and zero the + // performance counter for the current processor. + // + + HalpWriteCompareRegisterAndClear(DEFAULT_PROFILE_COUNT); + Prcb = KeGetCurrentPrcb(); + HalpPerformanceCounter[Prcb->Number].QuadPart = 0; + + // + // Restore IRQL to its previous value and return. + // + + KeLowerIrql(OldIrql); + return; +} + +ULONG +HalSetProfileInterval ( + IN ULONG Interval + ) + +/*++ + +Routine Description: + + This routine sets the profile interrupt interval. + +Arguments: + + Interval - Supplies the desired profile interval in 100ns units. + +Return Value: + + The actual profile interval. + +--*/ + +{ + + LARGE_INTEGER TempValue; + + // + // If the specified profile interval is less that the minimum profile + // interval or greater than the maximum profile interval, then set the + // profile interval to the minimum or maximum as appropriate. + // + + if (Interval < MINIMUM_PROFILE_INTERVAL) { + Interval = MINIMUM_PROFILE_INTERVAL; + + } else if (Interval > MAXIMUM_PROFILE_INTERVAL) { + Interval = MAXIMUM_PROFILE_INTERVAL; + } + + // + // First compute the profile count value and then back calculate the + // actual profile interval. + // + + TempValue.QuadPart = Int32x32To64(HalpProfileCountRate, Interval); + TempValue.QuadPart += ROUND_VALUE; + TempValue = RtlExtendedLargeIntegerDivide(TempValue, ONE_SECOND, NULL); + TempValue.QuadPart = Int32x32To64(TempValue.LowPart, ONE_SECOND); + TempValue = RtlExtendedLargeIntegerDivide(TempValue, HalpProfileCountRate, NULL); + HalpProfileInterval = TempValue.LowPart; + return HalpProfileInterval; +} + +VOID +HalStartProfileInterrupt ( + KPROFILE_SOURCE Source + ) + +/*++ + +Routine Description: + + This routine computes the profile count value, writes the compare + register, clears the count register, and updates the performance + counter. + + N.B. This routine must be called at PROFILE_LEVEL while holding the + profile lock. + +Arguments: + + Source - Supplies the profile source. + +Return Value: + + None. + +--*/ + +{ + + PKPRCB Prcb; + ULONG PreviousCount; + LARGE_INTEGER TempValue; + + // + // Compute the profile count from the current profile interval. + // + + TempValue.QuadPart = Int32x32To64(HalpProfileCountRate, + HalpProfileInterval); + + TempValue.QuadPart += ROUND_VALUE; + TempValue = RtlExtendedLargeIntegerDivide(TempValue, ONE_SECOND, NULL); + + // + // Write the compare register and clear the count register. + // + + PreviousCount = HalpWriteCompareRegisterAndClear(TempValue.LowPart); + + // + // Update the performance counter by adding in the previous count value. + // + + Prcb = KeGetCurrentPrcb(); + HalpPerformanceCounter[Prcb->Number].QuadPart += PreviousCount; + return; +} + +VOID +HalStopProfileInterrupt ( + KPROFILE_SOURCE Source + ) + +/*++ + +Routine Description: + + This routine sets the default count value, writes the compare + register, clears the count register, and updates the performance + counter. + + N.B. This routine must be called at PROFILE_LEVEL while holding the + profile lock. + +Arguments: + + Source - Supplies the profile source. + +Return Value: + + None. + +--*/ + +{ + + PKPRCB Prcb; + ULONG PreviousCount; + + // + // Write the compare register and clear the count register. + // + + PreviousCount = HalpWriteCompareRegisterAndClear(DEFAULT_PROFILE_COUNT); + + // + // Update the performance counter by adding in the previous count value. + // + + Prcb = KeGetCurrentPrcb(); + HalpPerformanceCounter[Prcb->Number].QuadPart += PreviousCount; + return; +} diff --git a/private/ntos/nthals/halsnip/mips/jxbeep.c b/private/ntos/nthals/halsnip/mips/jxbeep.c new file mode 100644 index 000000000..a2a99459b --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/jxbeep.c @@ -0,0 +1,132 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/jxbeep.c,v 1.1 1995/07/20 15:56:54 flo Exp $") + +/*++ + +Copyright (c) 1991-1994 Microsoft Corporation + +Module Name: + + jxbeep.c + +Abstract: + + This module implements the HAL speaker "beep" routines for a MIPS + system. + +Environment: + + Kernel mode + +Revision History: + +--*/ + +#include "halp.h" +#include "eisa.h" + +BOOLEAN +HalMakeBeep( + IN ULONG Frequency + ) + +/*++ + +Routine Description: + + This function sets the frequency of the speaker, causing it to sound a + tone. The tone will sound until the speaker is explicitly turned off, + so the driver is responsible for controlling the duration of the tone. + +Arguments: + + Frequency - Supplies the frequency of the desired tone. A frequency of + 0 means the speaker should be shut off. + +Return Value: + + TRUE - Operation was successful (frequency within range or zero). + FALSE - Operation was unsuccessful (frequency was out of range). + Current tone (if any) is unchanged. + +--*/ + +{ + + KIRQL OldIrql; + NMI_STATUS NmiStatus; + PEISA_CONTROL controlBase = HalpOnboardControlBase; + TIMER_CONTROL timerControl; + ULONG newCount; + BOOLEAN Result; + + // + // Raise IRQL to dispatch level and acquire the beep spin lock. + // + + KeAcquireSpinLock(&HalpBeepLock, &OldIrql); + + // + // Stop the speaker. + // + + *((PUCHAR)&NmiStatus) = READ_REGISTER_UCHAR(&controlBase->NmiStatus); + NmiStatus.SpeakerGate = 0; + NmiStatus.SpeakerData = 0; + WRITE_REGISTER_UCHAR(&controlBase->NmiStatus, *((PUCHAR)&NmiStatus)); + + // + // If the specified frequency is zero, then the speaker is to be stopped. + // + + if (Frequency == 0) { + Result = TRUE; + + } else { + + // + // If the new count has a magnitude less than 65,536 (0x10000), then + // set the speaker time to the correct mode. Otherwise, return a value + // of FALSE sinc ethe frequency is out of range. + // + + newCount = TIMER_CLOCK_IN / Frequency; + if (newCount >= 0x10000) { + Result = FALSE; + + } else { + + // + // Set the speaker timer to the correct mode. + // + + timerControl.BcdMode = 0; + timerControl.Mode = TM_SQUARE_WAVE; + timerControl.SelectByte = SB_LSB_THEN_MSB; + timerControl.SelectCounter = SELECT_COUNTER_2; + WRITE_REGISTER_UCHAR(&controlBase->CommandMode1, *((PUCHAR) &timerControl)); + + // + // Set the speaker timer to the correct mode. + // + + WRITE_REGISTER_UCHAR(&controlBase->SpeakerTone, (UCHAR)(newCount & 0xff)); + WRITE_REGISTER_UCHAR(&controlBase->SpeakerTone, (UCHAR)(newCount >> 8)); + + // + // Start the speaker. + // + + NmiStatus.SpeakerGate = 1; + NmiStatus.SpeakerData = 1; + WRITE_REGISTER_UCHAR(&controlBase->NmiStatus, *((PUCHAR) &NmiStatus)); + Result = TRUE; + } + } + + // + // Release the beep spin lock and lower IRQL to its previous value. + // + + KeReleaseSpinLock(&HalpBeepLock, OldIrql); + return Result; +} diff --git a/private/ntos/nthals/halsnip/mips/jxebsup.c b/private/ntos/nthals/halsnip/mips/jxebsup.c new file mode 100644 index 000000000..acae485bc --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/jxebsup.c @@ -0,0 +1,2760 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/jxebsup.c,v 1.6 1996/03/04 13:15:15 pierre Exp $") +/*++ + +Copyright (c) 1993-94 Siemens Nixdorf Informationssysteme AG +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + jxebsup.c + +Abstract: + + The module provides the ISA/EISA bus support for SNI systems. + + +--*/ + +#include "halp.h" +#include "eisa.h" + +// +// Define the context structure for use by the interrupt routine. +// + +typedef BOOLEAN (*PSECONDARY_DISPATCH)( + PVOID InterruptRoutine + ); + +// +// Declare the interrupt structure and spinlock for the intermediate EISA +// interrupt dispachter. +// + +KINTERRUPT HalpEisaInterrupt; +KINTERRUPT HalpOnboardInterrupt; + +// +// Define save area for EISA adapter objects. +// + +PADAPTER_OBJECT HalpEisaAdapter[8]; +PADAPTER_OBJECT HalpOnboardAdapter[8]; +PADAPTER_OBJECT HalpInternalAdapters[2]; + +// +// Define save area for EISA interrupt mask registers and level\edge control +// registers. +// + +UCHAR HalpEisaInterrupt1Mask; +UCHAR HalpEisaInterrupt2Mask; +UCHAR HalpEisaInterrupt1Level; +UCHAR HalpEisaInterrupt2Level; + +UCHAR HalpOnboardInterrupt1Mask; +UCHAR HalpOnboardInterrupt2Mask; +UCHAR HalpOnboardInterrupt1Level; +UCHAR HalpOnboardInterrupt2Level; + +VOID +HalpCopyBufferMap( + IN PMDL Mdl, + IN PTRANSLATION_ENTRY TranslationEntry, + IN PVOID CurrentVa, + IN ULONG Length, + IN BOOLEAN WriteToDevice + ); + + +NTSTATUS +HalAllocateAdapterChannel( + IN PADAPTER_OBJECT AdapterObject, + IN PWAIT_CONTEXT_BLOCK Wcb, + IN ULONG NumberOfMapRegisters, + IN PDRIVER_CONTROL ExecutionRoutine + ) +/*++ + +Routine Description: + + This routine allocates the adapter channel specified by the adapter object. + This is accomplished by placing the device object of the driver that wants + to allocate the adapter on the adapter's queue. If the queue is already + "busy", then the adapter has already been allocated, so the device object + is simply placed onto the queue and waits until the adapter becomes free. + + Once the adapter becomes free (or if it already is), then the driver's + execution routine is invoked. + + Also, a number of map registers may be allocated to the driver by specifying + a non-zero value for NumberOfMapRegisters. Then the map register must be + allocated from the master adapter. Once there are a sufficient number of + map registers available, then the execution routine is called and the + base address of the allocated map registers in the adapter is also passed + to the driver's execution routine. + +Arguments: + + AdapterObject - Pointer to the adapter control object to allocate to the + driver. + + Wcb - Supplies a wait context block for saving the allocation parameters. + The DeviceObject, CurrentIrp and DeviceContext should be initalized. + + NumberOfMapRegisters - The number of map registers that are to be allocated + from the channel, if any. + + ExecutionRoutine - The address of the driver's execution routine that is + invoked once the adapter channel (and possibly map registers) have been + allocated. + +Return Value: + + Returns STATUS_SUCESS unless too many map registers are requested. + +Notes: + + Note that this routine MUST be invoked at DISPATCH_LEVEL or above. + +--*/ +{ + + PADAPTER_OBJECT MasterAdapter; + BOOLEAN Busy = FALSE; + IO_ALLOCATION_ACTION Action; + KIRQL Irql; + LONG MapRegisterNumber; + + // + // Begin by obtaining a pointer to the master adapter associated with this + // request. + // + + MasterAdapter = AdapterObject->MasterAdapter; + + // + // Initialize the device object's wait context block in case this device + // must wait before being able to allocate the adapter. + // + + Wcb->DeviceRoutine = ExecutionRoutine; + Wcb->NumberOfMapRegisters = NumberOfMapRegisters; + + // + // Allocate the adapter object for this particular device. If the + // adapter cannot be allocated because it has already been allocated + // to another device, then return to the caller now; otherwise, + // continue. + // + + if (!KeInsertDeviceQueue( &AdapterObject->ChannelWaitQueue, + &Wcb->WaitQueueEntry )) { + + // + // Save the parameters in case there are not enough map registers. + // + + AdapterObject->NumberOfMapRegisters = NumberOfMapRegisters; + AdapterObject->CurrentWcb = Wcb; + + // + // The adapter was not busy so it has been allocated. Now check + // to see whether this driver wishes to allocate any map registers. + // Ensure that this adapter has enough total map registers + // to satisfy the request. + // + + // + // For PCI devices we don't have to deal with + // map registers + // + + if (NumberOfMapRegisters != 0 && AdapterObject->NeedsMapRegisters && AdapterObject->InterfaceType != PCIBus) { + + // + // Lock the map register bit map and the adapter queue in the + // master adapter object. The channel structure offset is used as + // a hint for the register search. + // + + if (NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel) { + AdapterObject->NumberOfMapRegisters = 0; + IoFreeAdapterChannel(AdapterObject); + return(STATUS_INSUFFICIENT_RESOURCES); + } + + KeAcquireSpinLock( &MasterAdapter->SpinLock, &Irql ); + + MapRegisterNumber = -1; + + if (IsListEmpty( &MasterAdapter->AdapterQueue)) { + + MapRegisterNumber = RtlFindClearBitsAndSet( + MasterAdapter->MapRegisters, + NumberOfMapRegisters, + 0 + ); + } + + if (MapRegisterNumber == -1) { + + // + // There were not enough free map registers. Queue this request + // on the master adapter where is will wait until some registers + // are deallocated. + // + + InsertTailList( &MasterAdapter->AdapterQueue, + &AdapterObject->AdapterQueue + ); + Busy = 1; + + } else { + + // + // Calculate the map register base from the allocated map + // register and base of the master adapter object. + // + + AdapterObject->MapRegisterBase = ((PTRANSLATION_ENTRY) + MasterAdapter->MapRegisterBase + MapRegisterNumber); + + // + // Set the no scatter/gather flag if scatter/gather not + // supported. + // + + if (!AdapterObject->ScatterGather) { + + AdapterObject->MapRegisterBase = (PVOID) + ((ULONG) AdapterObject->MapRegisterBase | NO_SCATTER_GATHER); + + } + } + + KeReleaseSpinLock( &MasterAdapter->SpinLock, Irql ); + + } else { + + AdapterObject->MapRegisterBase = NULL; + AdapterObject->NumberOfMapRegisters = 0; + } + + // + // If there were either enough map registers available or no map + // registers needed to be allocated, invoke the driver's execution + // routine now. + // + + if (!Busy) { + + AdapterObject->CurrentWcb = Wcb; + Action = ExecutionRoutine( Wcb->DeviceObject, + Wcb->CurrentIrp, + AdapterObject->MapRegisterBase, + Wcb->DeviceContext ); + + // + // If the driver would like to have the adapter deallocated, + // then release the adapter object. + // + + if (Action == DeallocateObject) { + + IoFreeAdapterChannel( AdapterObject ); + + } else if (Action == DeallocateObjectKeepRegisters) { + + // + // Set the NumberOfMapRegisters = 0 in the adapter object. + // This will keep IoFreeAdapterChannel from freeing the + // registers. After this it is the driver's responsiblity to + // keep track of the number of map registers. + // + + AdapterObject->NumberOfMapRegisters = 0; + IoFreeAdapterChannel(AdapterObject); + + } + } + } + + + return(STATUS_SUCCESS); + +} + +PADAPTER_OBJECT +HalGetAdapter( + IN PDEVICE_DESCRIPTION DeviceDescriptor, + OUT PULONG NumberOfMapRegisters + ) + +/*++ + +Routine Description: + + This function returns the appropriate adapter object for the device defined + in the device description structure. This code works for Isa and Eisa + systems. + +Arguments: + + DeviceDescriptor - Supplies a description of the device. + + NumberOfMapRegisters - Returns the maximum number of map registers which + may be allocated by the device driver. + +Return Value: + + A pointer to the requested adapter object or NULL if an adapter could not + be created. + +--*/ + +{ + PADAPTER_OBJECT adapterObject, tmpAdapterObject; + PVOID adapterBaseVa; + ULONG channelNumber; + ULONG controllerNumber; + DMA_EXTENDED_MODE extendedMode; + UCHAR adapterMode; + ULONG numberOfMapRegisters; + BOOLEAN useChannel; + ULONG maximumLength; + UCHAR DataByte; + PEISA_CONTROL controlBase; + + if (MasterAdapterObject == NULL) + MasterAdapterObject = HalpAllocateAdapter( + 10, + (PVOID) -1, + NULL + ); + + if ((DeviceDescriptor->InterfaceType == Internal) || (DeviceDescriptor->InterfaceType == PCIBus)) { + + if (DeviceDescriptor->Master) { + + // The SNI machines support only Master Devices on the + // internal Bus; most of this stuff is the same as for EISA + + // Limit the maximum length to 2 GB this is done so that the BYTES_TO_PAGES + // macro works correctly. + // + + maximumLength = DeviceDescriptor->MaximumLength & 0x7fffffff; + + // + // Determine the number of map registers for this device. + // + + if ((DeviceDescriptor->ScatterGather) || (DeviceDescriptor->InterfaceType == PCIBus)) { + + // + // Since the device support scatter/Gather then map registers are not + // required. + // + + numberOfMapRegisters = 0; + + } else { + + // + // Determine the number of map registers required based on the maximum + // transfer length, up to a maximum number. + // + + numberOfMapRegisters = BYTES_TO_PAGES(maximumLength) + + 1; + } + + // + // Allocate an adapter object. + // + + adapterObject = (PADAPTER_OBJECT) HalpAllocateAdapter( + numberOfMapRegisters, + NULL, + NULL + ); + + if (adapterObject == NULL) { + return(NULL); + } + + // + // Set the maximum number of map registers for this channel bus on + // the number requested and the type of device. + // + + if (numberOfMapRegisters) { + + // + // The specified number of registers are actually allowed to be + // allocated. + // + + adapterObject->MapRegistersPerChannel = numberOfMapRegisters; + + + // + // Master I/O devices use several sets of map registers double + // their commitment. + // + + MasterAdapterObject->CommittedMapRegisters += + numberOfMapRegisters * 5; + + // + // If the committed map registers is signicantly greater than the + // number allocated then grow the map buffer. + // + + if (MasterAdapterObject->CommittedMapRegisters > + MasterAdapterObject->NumberOfMapRegisters ) { + HalpGrowMapBuffers( + MasterAdapterObject, + INCREMENT_MAP_BUFFER_SIZE + ); + } + + adapterObject->NeedsMapRegisters = TRUE; + + } else { + + // calculated Count for allocation was 0 ... + // ScatterGather Device on internal Bus + // No real map registers were allocated. If this is a master + // device, then the device can have as may registers as it wants. + // + + adapterObject->NeedsMapRegisters = FALSE; + + adapterObject->MapRegistersPerChannel = BYTES_TO_PAGES( + maximumLength + ) + + 1; + } + + adapterObject->InterfaceType = DeviceDescriptor->InterfaceType; + adapterObject->ScatterGather = DeviceDescriptor->ScatterGather; + *NumberOfMapRegisters = adapterObject->MapRegistersPerChannel; + adapterObject->MasterDevice = TRUE; + return (adapterObject); + + } // end of Master Device + + } // end of Internal Interface + +//+++++++++++++++EISA/ISA/MCA etc ...++++++++++++++++++++++++++++++++++++ + + // + // Determine if the the channel number is important. Master cards on + // Eisa and Mca do not use a channel number. + // + + if (DeviceDescriptor->InterfaceType != Isa && + DeviceDescriptor->Master) { + + useChannel = FALSE; + } else { + + useChannel = TRUE; + } + + // + // determine the controlBase, depending on Interface Type + // + + // + // Isa and Eisa Requests have to go to the Eisa Controller on the + // Eisa Extension, onboard components (Floppy) have to have the InterfaceType + // Internal in the Device Description !!! + // + if(DeviceDescriptor->InterfaceType == PCIBus) { + DbgBreakPoint(); + } + + // + // we direct all to the + // PC core (also if UseChannel = TRUE and InterfaceType == Internal ) + // + + controlBase = (PEISA_CONTROL)HalpOnboardControlBase; + + // + // Support for ISA local bus machines: + // If the driver is a Master but really does not want a channel since it + // is using the local bus DMA, just don't use an ISA channel. + // + + if (DeviceDescriptor->InterfaceType == Isa && + DeviceDescriptor->DmaChannel > 7) { + + useChannel = FALSE; + } + + // + // Determine if Eisa DMA is supported. + // + + if (DeviceDescriptor->InterfaceType == Eisa) { + + WRITE_REGISTER_UCHAR(&(controlBase)->DmaPageHighPort.Channel2, 0x55); + DataByte = READ_REGISTER_UCHAR(&(controlBase)->DmaPageHighPort.Channel2); + + if (DataByte == 0x55) { + HalpEisaDma = TRUE; + } + + } + + // + // Limit the maximum length to 2 GB this is done so that the BYTES_TO_PAGES + // macro works correctly. + // + + maximumLength = DeviceDescriptor->MaximumLength & 0x7fffffff; + + // + // Channel 4 cannot be used since it is used for chaining. Return null if + // it is requested. + // + + if (DeviceDescriptor->DmaChannel == 4 && useChannel) { + return(NULL); + } + + // + // Determine the number of map registers for this device. + // + + if (DeviceDescriptor->ScatterGather && (LessThan16Mb || + DeviceDescriptor->InterfaceType == Eisa)) { + + // + // Since the device support scatter/Gather then map registers are not + // required. + // + + numberOfMapRegisters = 0; + + } else { + + // + // Determine the number of map registers required based on the maximum + // transfer length, up to a maximum number. + // + + numberOfMapRegisters = BYTES_TO_PAGES(maximumLength) + + 1; + numberOfMapRegisters = numberOfMapRegisters > MAXIMUM_ISA_MAP_REGISTER ? + MAXIMUM_ISA_MAP_REGISTER : numberOfMapRegisters; + + // + // Make sure there where enough registers allocated initalize to support + // this size relaibly. This implies there must be to chunks equal to + // the allocatd size. This is only a problem on Isa systems where the + // map buffers cannot cross 64KB boundtires. + // + + if (!HalpEisaDma && + numberOfMapRegisters > HalpMapBufferSize / (PAGE_SIZE * 2)) { + + numberOfMapRegisters = (HalpMapBufferSize / (PAGE_SIZE * 2)); + } + // + // If the device is not a master and does scatter/Gather, + // then it only needs one map register + // + + if (DeviceDescriptor->ScatterGather && !DeviceDescriptor->Master) { + + numberOfMapRegisters = 1; + } + } + + // + // Set the channel number number. + // + + channelNumber = DeviceDescriptor->DmaChannel & 0x03; + + // + // Set the adapter base address to the Base address register and controller + // number. + // + + if (!(DeviceDescriptor->DmaChannel & 0x04)) { + + controllerNumber = 1; + adapterBaseVa = (PVOID) &(controlBase)->Dma1BasePort; + + } else { + + controllerNumber = 2; + adapterBaseVa = &(controlBase)->Dma2BasePort; + + } + + // + // Determine if a new adapter object is necessary. If so then allocate it. + // + + tmpAdapterObject = HalpOnboardAdapter[DeviceDescriptor->DmaChannel]; + + + if (useChannel && tmpAdapterObject != NULL) { + + adapterObject = tmpAdapterObject; + + if (adapterObject->NeedsMapRegisters) { + + if (numberOfMapRegisters > adapterObject->MapRegistersPerChannel) { + + adapterObject->MapRegistersPerChannel = numberOfMapRegisters; + } + } + } else { + + // + // Allocate an adapter object. + // + + adapterObject = (PADAPTER_OBJECT) HalpAllocateAdapter( + numberOfMapRegisters, + adapterBaseVa, + NULL + ); + + if (adapterObject == NULL) { + + return(NULL); + + } + + if (useChannel) { + + HalpOnboardAdapter[DeviceDescriptor->DmaChannel] = adapterObject; + + } + + // + // Set the maximum number of map registers for this channel bus on + // the number requested and the type of device. + // + + if (numberOfMapRegisters) { + + // + // The specified number of registers are actually allowed to be + // allocated. + // + + adapterObject->MapRegistersPerChannel = numberOfMapRegisters; + + // + // Increase the commitment for the map registers. + // + + if (DeviceDescriptor->Master) { + + // + // Master I/O devices use several sets of map registers double + // their commitment. + // + + MasterAdapterObject->CommittedMapRegisters += + numberOfMapRegisters * 5; + + } else { + + MasterAdapterObject->CommittedMapRegisters += + numberOfMapRegisters; + + } + + // + // If the committed map registers is signicantly greater than the + // number allocated then grow the map buffer. + // + + if (MasterAdapterObject->CommittedMapRegisters > + MasterAdapterObject->NumberOfMapRegisters) { + + HalpGrowMapBuffers( + MasterAdapterObject, + INCREMENT_MAP_BUFFER_SIZE + ); + } + + adapterObject->NeedsMapRegisters = TRUE; + + } else { + + // + // No real map registers were allocated. If this is a master + // device, then the device can have as may registers as it wants. + // + + adapterObject->NeedsMapRegisters = FALSE; + + if (DeviceDescriptor->Master) { + + adapterObject->MapRegistersPerChannel = BYTES_TO_PAGES( + maximumLength + ) + + 1; + + } else { + + // + // The device only gets one register. It must call + // IoMapTransfer repeatedly to do a large transfer. + // + + adapterObject->MapRegistersPerChannel = 1; + } + } + } + + adapterObject->InterfaceType = DeviceDescriptor->InterfaceType; + adapterObject->ScatterGather = DeviceDescriptor->ScatterGather; + *NumberOfMapRegisters = adapterObject->MapRegistersPerChannel; + + if (DeviceDescriptor->Master) { + + adapterObject->MasterDevice = TRUE; + + } else { + + adapterObject->MasterDevice = FALSE; + + } + + // + // If the channel number is not used then we are finished. The rest of + // the work deals with channels. + // + + if (!useChannel) { + return(adapterObject); + } + + // + // Setup the pointers to all the random registers. + // + + adapterObject->ChannelNumber = (UCHAR) channelNumber; + + if (controllerNumber == 1) { + + switch ((UCHAR)channelNumber) { + + case 0: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel0; + break; + + case 1: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel1; + break; + + case 2: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel2; + break; + + case 3: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel3; + break; + } + + // + // Set the adapter number. + // + + adapterObject->AdapterNumber = 1; + + // + // Save the extended mode register address. + // + + adapterBaseVa = + &(controlBase)->Dma1ExtendedModePort; + + } else { + + switch (channelNumber) { + case 1: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel5; + break; + + case 2: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel6; + break; + + case 3: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel7; + break; + } + + // + // Set the adapter number. + // + + adapterObject->AdapterNumber = 2; + + // + // Save the extended mode register address. + // + adapterBaseVa = + &(controlBase)->Dma2ExtendedModePort; + + } + + + adapterObject->Width16Bits = FALSE; + + if (HalpEisaDma) { + + // + // Initialzie the extended mode port. + // + + *((PUCHAR) &extendedMode) = 0; + extendedMode.ChannelNumber = (UCHAR)channelNumber; + + switch (DeviceDescriptor->DmaSpeed) { + case Compatible: + extendedMode.TimingMode = COMPATIBLITY_TIMING; + break; + + case TypeA: + extendedMode.TimingMode = TYPE_A_TIMING; + break; + + case TypeB: + extendedMode.TimingMode = TYPE_B_TIMING; + break; + + case TypeC: + extendedMode.TimingMode = BURST_TIMING; + break; + + default: + ObDereferenceObject( adapterObject ); + return(NULL); + + } + + switch (DeviceDescriptor->DmaWidth) { + case Width8Bits: + extendedMode.TransferSize = BY_BYTE_8_BITS; + break; + + case Width16Bits: + extendedMode.TransferSize = BY_BYTE_16_BITS; + + // + // Note Width16bits should not be set here because there is no need + // to shift the address and the transfer count. + // + + break; + + case Width32Bits: + extendedMode.TransferSize = BY_BYTE_32_BITS; + break; + + default: + ObDereferenceObject( adapterObject ); + return(NULL); + + } + + WRITE_REGISTER_UCHAR( adapterBaseVa, *((PUCHAR) &extendedMode)); + + } else if (!DeviceDescriptor->Master) { + + switch (DeviceDescriptor->DmaWidth) { + case Width8Bits: + + // + // The channel must use controller 1. + // + + if (controllerNumber != 1) { + ObDereferenceObject( adapterObject ); + return(NULL); + } + + break; + + case Width16Bits: + + // + // The channel must use controller 2. + // + + if (controllerNumber != 2) { + ObDereferenceObject( adapterObject ); + return(NULL); + } + + adapterObject->Width16Bits = TRUE; + break; + + default: + ObDereferenceObject( adapterObject ); + return(NULL); + + } + } + + // + // Initialize the adapter mode register value to the correct parameters, + // and save them in the adapter object. + // + + adapterMode = 0; + ((PDMA_EISA_MODE) &adapterMode)->Channel = adapterObject->ChannelNumber; + + if (DeviceDescriptor->Master) { + + ((PDMA_EISA_MODE) &adapterMode)->RequestMode = CASCADE_REQUEST_MODE; + + // + // Set the mode, and enable the request. + // + + if (adapterObject->AdapterNumber == 1) { + + // + // This request is for DMA controller 1 + // + + PDMA1_CONTROL dmaControl; + + dmaControl = adapterObject->AdapterBaseVa; + + WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode ); + + // + // Unmask the DMA channel. + // + + WRITE_REGISTER_UCHAR( + &dmaControl->SingleMask, + (UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber) + ); + + } else { + + // + // This request is for DMA controller 1 + // + + PDMA2_CONTROL dmaControl; + + dmaControl = adapterObject->AdapterBaseVa; + + WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode ); + + // + // Unmask the DMA channel. + // + + WRITE_REGISTER_UCHAR( + &dmaControl->SingleMask, + (UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber) + ); + + } + + } else if (DeviceDescriptor->DemandMode) { + + ((PDMA_EISA_MODE) &adapterMode)->RequestMode = DEMAND_REQUEST_MODE; + + } else { + + ((PDMA_EISA_MODE) &adapterMode)->RequestMode = SINGLE_REQUEST_MODE; + + } + + if (DeviceDescriptor->AutoInitialize) { + + ((PDMA_EISA_MODE) &adapterMode)->AutoInitialize = 1; + + } + + adapterObject->AdapterMode = adapterMode; + + return(adapterObject); +} + +PHYSICAL_ADDRESS +IoMapTransfer( + IN PADAPTER_OBJECT AdapterObject, + IN PMDL Mdl, + IN PVOID MapRegisterBase, + IN PVOID CurrentVa, + IN OUT PULONG Length, + IN BOOLEAN WriteToDevice + ) + +/*++ + +Routine Description: + + This routine is invoked to set up the map registers in the DMA controller + to allow a transfer to or from a device. + +Arguments: + + AdapterObject - Pointer to the adapter object representing the DMA + controller channel that has been allocated. + + Mdl - Pointer to the MDL that describes the pages of memory that are + being read or written. + + MapRegisterBase - The address of the base map register that has been + allocated to the device driver for use in mapping the transfer. + + CurrentVa - Current virtual address in the buffer described by the MDL + that the transfer is being done to or from. + + Length - Supplies the length of the transfer. This determines the + number of map registers that need to be written to map the transfer. + Returns the length of the transfer which was actually mapped. + + WriteToDevice - Boolean value that indicates whether this is a write + to the device from memory (TRUE), or vice versa. + +Return Value: + + Returns the logical address that should be used bus master controllers. + +--*/ + +{ + BOOLEAN useBuffer; + ULONG transferLength; + ULONG logicalAddress; + PHYSICAL_ADDRESS returnAddress; + ULONG index; + PULONG pageFrame; + PUCHAR bytePointer; + UCHAR adapterMode; + UCHAR dataByte; + PTRANSLATION_ENTRY translationEntry; + ULONG pageOffset; + KIRQL Irql; + ULONG partialLength; + ULONG temp; + PEISA_CONTROL controlBase; + + // for minitower or Eisa Interface Type (default case) + + controlBase = (PEISA_CONTROL)HalpOnboardControlBase; + + pageOffset = BYTE_OFFSET(CurrentVa); + + // + // Calculate how much of the transfer is contiguous. + // + + transferLength = PAGE_SIZE - pageOffset; + pageFrame = (PULONG)(Mdl+1); + pageFrame += ((ULONG) CurrentVa - (ULONG) Mdl->StartVa) >> PAGE_SHIFT; + logicalAddress = (*pageFrame << PAGE_SHIFT) + pageOffset; + + // + // If the buffer is contigous and does not cross a 64 K bountry then + // just extend the buffer. The 64 K bountry restriction does not apply + // to Eisa systems. + // + + while( transferLength < *Length ){ + + if (*pageFrame + 1 != *(pageFrame + 1)) { + break; + } + + transferLength += PAGE_SIZE; + pageFrame++; + + } + + // + // Limit the transferLength to the requested Length. + // + + transferLength = transferLength > *Length ? *Length : transferLength; + + // + // Determine if the data transfer needs to use the map buffer. + // + + if (MapRegisterBase != NULL) { + + // + // Strip no scatter/gather flag. + // + + translationEntry = (PTRANSLATION_ENTRY) ((ULONG) MapRegisterBase & ~NO_SCATTER_GATHER); + + if ((ULONG) MapRegisterBase & NO_SCATTER_GATHER + && transferLength < *Length) { + + logicalAddress = translationEntry->PhysicalAddress + pageOffset; + translationEntry->Index = COPY_BUFFER; + index = 0; + transferLength = *Length; + useBuffer = TRUE; + + } else { + + // + // If there are map registers, then update the index to indicate + // how many have been used. + // + + useBuffer = FALSE; + index = translationEntry->Index; + translationEntry->Index += ADDRESS_AND_SIZE_TO_SPAN_PAGES( + CurrentVa, + transferLength + ); + } + + // + // It must require memory to be at less than 16 MB. If the + // logical address is greater than 16MB then map registers must be used + // + + if (logicalAddress+transferLength >= MAXIMUM_PHYSICAL_ADDRESS) { + + logicalAddress = (translationEntry + index)->PhysicalAddress + + pageOffset; + useBuffer = TRUE; + + if ((ULONG) MapRegisterBase & NO_SCATTER_GATHER) { + + translationEntry->Index = COPY_BUFFER; + index = 0; + + } + + } + + // + // Copy the data if necessary. + // + + if (useBuffer && WriteToDevice) { + + temp = transferLength; + + transferLength = PAGE_SIZE - BYTE_OFFSET(CurrentVa); + partialLength = transferLength; + pageFrame = (PULONG)(Mdl+1); + pageFrame += ((ULONG) CurrentVa - (ULONG) Mdl->StartVa) >> PAGE_SHIFT; + + while( transferLength <= *Length ) { + + HalpCopyBufferMap( + Mdl, + translationEntry + index, + CurrentVa, + partialLength, + WriteToDevice + ); + + (PCCHAR) CurrentVa += partialLength; + partialLength = PAGE_SIZE; + + // + // Note that transferLength indicates the amount which will be + // transfered after the next loop; thus, it is updated with the + // new partial length. + // + + transferLength += partialLength; + pageFrame++; + translationEntry++; + + } + + // + // Process the any remaining residue. + // + + partialLength = *Length - transferLength + partialLength; + + if (partialLength) { + + HalpCopyBufferMap( + Mdl, + translationEntry + index, + CurrentVa, + partialLength, + WriteToDevice + ); + + } + + transferLength = temp; + + } + } + + // + // Return the length. + // + + *Length = transferLength; + + // + // We only support 32 bits, but the return is 64. Just + // zero extend + // + + returnAddress.LowPart = logicalAddress; + returnAddress.HighPart = 0; + + // + // If no adapter was specificed then there is no more work to do so + // return. + // + + if (AdapterObject == NULL || AdapterObject->MasterDevice) { + + return(returnAddress); + } + + // + // Determine the mode based on the transfer direction. + // + + adapterMode = AdapterObject->AdapterMode; + ((PDMA_EISA_MODE) &adapterMode)->TransferType = (UCHAR) (WriteToDevice ? + WRITE_TRANSFER : READ_TRANSFER); + + bytePointer = (PUCHAR) &logicalAddress; + + if (AdapterObject->Width16Bits) { + + // + // If this is a 16 bit transfer then adjust the length and the address + // for the 16 bit DMA mode. + // + + transferLength >>= 1; + + // + // In 16 bit DMA mode the low 16 bits are shifted right one and the + // page register value is unchanged. So save the page register value + // and shift the logical address then restore the page value. + // + + dataByte = bytePointer[2]; + logicalAddress >>= 1; + bytePointer[2] = dataByte; + + } + + + // + // grab the spinlock for the system DMA controller + // + + KeAcquireSpinLock( &AdapterObject->MasterAdapter->SpinLock, &Irql ); + + // + // Determine the controller number based on the Adapter number. + // + + if (AdapterObject->AdapterNumber == 1) { + + // + // This request is for DMA controller 1 + // + + PDMA1_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_REGISTER_UCHAR( &dmaControl->ClearBytePointer, 0 ); + + WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode ); + + WRITE_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseAddress, + bytePointer[0] + ); + + WRITE_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseAddress, + bytePointer[1] + ); + + WRITE_REGISTER_UCHAR( + ((PUCHAR) &(controlBase)->DmaPageLowPort) + + (ULONG)AdapterObject->PagePort, + bytePointer[2] + ); + + // + // Write the high page register with zero value. This enable a special mode + // which allows ties the page register and base count into a single 24 bit + // address register. + // + + WRITE_REGISTER_UCHAR( + ((PUCHAR) &(controlBase)->DmaPageHighPort) + + (ULONG)AdapterObject->PagePort, + 0 + ); + + // + // Notify DMA chip of the length to transfer. + // + + WRITE_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount, + (UCHAR) ((transferLength - 1) & 0xff) + ); + + WRITE_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount, + (UCHAR) ((transferLength - 1) >> 8) + ); + + + // + // Set the DMA chip to read or write mode; and unmask it. + // + + WRITE_REGISTER_UCHAR( + &dmaControl->SingleMask, + (UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber) + ); + + } else { + + // + // This request is for DMA controller 2 + // + + PDMA2_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_REGISTER_UCHAR( &dmaControl->ClearBytePointer, 0 ); + + WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode ); + + WRITE_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseAddress, + bytePointer[0] + ); + + WRITE_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseAddress, + bytePointer[1] + ); + + WRITE_REGISTER_UCHAR( + ((PUCHAR) &(controlBase)->DmaPageLowPort) + + (ULONG)AdapterObject->PagePort, + bytePointer[2] + ); + + // + // Write the high page register with zero value. This enable a special mode + // which allows ties the page register and base count into a single 24 bit + // address register. + // + + WRITE_REGISTER_UCHAR( + ((PUCHAR) &(controlBase)->DmaPageHighPort) + + (ULONG)AdapterObject->PagePort, + 0 + ); + + // + // Notify DMA chip of the length to transfer. + // + + WRITE_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount, + (UCHAR) ((transferLength - 1) & 0xff) + ); + + WRITE_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount, + (UCHAR) ((transferLength - 1) >> 8) + ); + + + // + // Set the DMA chip to read or write mode; and unmask it. + // + + WRITE_REGISTER_UCHAR( + &dmaControl->SingleMask, + (UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber) + ); + + } + KeReleaseSpinLock (&AdapterObject->MasterAdapter->SpinLock, Irql); + + return(returnAddress); +} + +BOOLEAN +IoFlushAdapterBuffers( + IN PADAPTER_OBJECT AdapterObject, + IN PMDL Mdl, + IN PVOID MapRegisterBase, + IN PVOID CurrentVa, + IN ULONG Length, + IN BOOLEAN WriteToDevice + ) + +/*++ + +Routine Description: + + This routine flushes the DMA adapter object buffers. For the Jazz system + its clears the enable flag which aborts the dma. + +Arguments: + + AdapterObject - Pointer to the adapter object representing the DMA + controller channel. + + Mdl - A pointer to a Memory Descriptor List (MDL) that maps the locked-down + buffer to/from which the I/O occured. + + MapRegisterBase - A pointer to the base of the map registers in the adapter + or DMA controller. + + CurrentVa - The current virtual address in the buffer described the the Mdl + where the I/O operation occurred. + + Length - Supplies the length of the transfer. + + WriteToDevice - Supplies a BOOLEAN value that indicates the direction of + the data transfer was to the device. + +Return Value: + + TRUE - No errors are detected so the transfer must succeed. + +--*/ + +{ + PTRANSLATION_ENTRY translationEntry; + PULONG pageFrame; + ULONG transferLength; + ULONG partialLength; + BOOLEAN masterDevice; + + pageFrame = (PULONG)(Mdl+1); + pageFrame += ((ULONG) CurrentVa - (ULONG) Mdl->StartVa) >> PAGE_SHIFT; + + masterDevice = AdapterObject == NULL || AdapterObject->MasterDevice ? + TRUE : FALSE; + + // + // If this is a slave device, then stop the DMA controller. + // + + if (!masterDevice) { + + // + // Mask the DMA request line so that DMA requests cannot occur. + // + + if (AdapterObject->AdapterNumber == 1) { + + // + // This request is for DMA controller 1 + // + + PDMA1_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_REGISTER_UCHAR( + &dmaControl->SingleMask, + (UCHAR) (DMA_SETMASK | AdapterObject->ChannelNumber) + ); + + } else { + + // + // This request is for DMA controller 2 + // + + PDMA2_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_REGISTER_UCHAR( + &dmaControl->SingleMask, + (UCHAR) (DMA_SETMASK | AdapterObject->ChannelNumber) + ); + + } + + } + + if (MapRegisterBase == NULL) { + return(TRUE); + } + + // + // Determine if the data needs to be copied to the orginal buffer. + // This only occurs if the data tranfer is from the device, the + // MapReisterBase is not NULL and the transfer spans a page. + // + + if (!WriteToDevice) { + + // + // Strip no scatter/gather flag. + // + + translationEntry = (PTRANSLATION_ENTRY) ((ULONG) MapRegisterBase & ~NO_SCATTER_GATHER); + + // + // If this is not a master device, then just transfer the buffer. + // + + if ((ULONG) MapRegisterBase & NO_SCATTER_GATHER) { + + if (translationEntry->Index == COPY_BUFFER) { + + if (!masterDevice) { + + // + // Copy only the bytes that have actually been transfered. + // + + Length -= HalReadDmaCounter(AdapterObject); + + } + + // + // The adapter does not support scatter/gather copy the buffer. + // + + transferLength = PAGE_SIZE - BYTE_OFFSET(CurrentVa); + partialLength = transferLength; + pageFrame = (PULONG)(Mdl+1); + pageFrame += ((ULONG) CurrentVa - (ULONG) Mdl->StartVa) >> PAGE_SHIFT; + + while( transferLength <= Length ){ + + HalpCopyBufferMap( + Mdl, + translationEntry, + CurrentVa, + partialLength, + WriteToDevice + ); + + (PCCHAR) CurrentVa += partialLength; + partialLength = PAGE_SIZE; + + // + // Note that transferLength indicates the amount which will be + // transfered after the next loop; thus, it is updated with the + // new partial length. + // + + transferLength += partialLength; + pageFrame++; + translationEntry++; + } + + // + // Process the any remaining residue. + // + + partialLength = Length - transferLength + partialLength; + + if (partialLength) { + + HalpCopyBufferMap( + Mdl, + translationEntry, + CurrentVa, + partialLength, + WriteToDevice + ); + + } + } + + } else { + + // + // Cycle through the pages of the transfer to determine if there + // are any which need to be copied back. + // + + transferLength = PAGE_SIZE - BYTE_OFFSET(CurrentVa); + partialLength = transferLength; + pageFrame = (PULONG)(Mdl+1); + pageFrame += ((ULONG) CurrentVa - (ULONG) Mdl->StartVa) >> PAGE_SHIFT; + + while( transferLength <= Length ){ + + if (*pageFrame >= BYTES_TO_PAGES(MAXIMUM_PHYSICAL_ADDRESS)) { + + HalpCopyBufferMap( + Mdl, + translationEntry, + CurrentVa, + partialLength, + WriteToDevice + ); + + } + + (PCCHAR) CurrentVa += partialLength; + partialLength = PAGE_SIZE; + + // + // Note that transferLength indicates the amount which will be + // transfered after the next loop; thus, it is updated with the + // new partial length. + // + + transferLength += partialLength; + pageFrame++; + translationEntry++; + } + + // + // Process the any remaining residue. + // + + partialLength = Length - transferLength + partialLength; + + if (partialLength) { + + if (*pageFrame >= BYTES_TO_PAGES(MAXIMUM_PHYSICAL_ADDRESS)) { + + HalpCopyBufferMap( + Mdl, + translationEntry, + CurrentVa, + partialLength, + WriteToDevice + ); + + } + } + + } + } + + // + // Strip no scatter/gather flag. + // + + translationEntry = (PTRANSLATION_ENTRY) ((ULONG) MapRegisterBase & ~NO_SCATTER_GATHER); + + // + // Clear index in map register. + // + + translationEntry->Index = 0; + + return TRUE; +} + +ULONG +HalReadDmaCounter( + IN PADAPTER_OBJECT AdapterObject + ) +/*++ + +Routine Description: + + This function reads the DMA counter and returns the number of bytes left + to be transfered. + +Arguments: + + AdapterObject - Supplies a pointer to the adapter object to be read. + +Return Value: + + Returns the number of bytes still be be transfered. + +--*/ + +{ + ULONG count; + ULONG high; + KIRQL Irql; + + // + // Grab the spinlock for the system DMA controller. + // + + KeAcquireSpinLock( &AdapterObject->MasterAdapter->SpinLock, &Irql ); + + // + // Determine the controller number based on the Adapter number. + // + + if (AdapterObject->AdapterNumber == 1) { + + // + // This request is for DMA controller 1 + // + + PDMA1_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_REGISTER_UCHAR( &dmaControl->ClearBytePointer, 0 ); + + + // + // Initialize count to a value which will not match. + // + + count = 0xFFFF00; + + // + // Loop until the same high byte is read twice. + // + + do { + + high = count; + + WRITE_REGISTER_UCHAR( &dmaControl->ClearBytePointer, 0 ); + + // + // Read the current DMA count. + // + + count = READ_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount + ); + + count |= READ_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount + ) << 8; + + } while ((count & 0xFFFF00) != (high & 0xFFFF00)); + + } else { + + // + // This request is for DMA controller 2 + // + + PDMA2_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_REGISTER_UCHAR( &dmaControl->ClearBytePointer, 0 ); + + // + // Initialize count to a value which will not match. + // + + count = 0xFFFF00; + + // + // Loop until the same high byte is read twice. + // + + do { + + high = count; + + WRITE_REGISTER_UCHAR( &dmaControl->ClearBytePointer, 0 ); + + // + // Read the current DMA count. + // + + count = READ_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount + ); + + count |= READ_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount + ) << 8; + + } while ((count & 0xFFFF00) != (high & 0xFFFF00)); + + + } + + // + // Release the spinlock for the system DMA controller. + // + + KeReleaseSpinLock( &AdapterObject->MasterAdapter->SpinLock, Irql ); + + // + // The DMA counter has a bias of one and can only be 16 bit long. + // + + count = (count + 1) & 0xFFFF; + + // + // If this is a 16 bit dma the multiply the count by 2. + // + + if (AdapterObject->Width16Bits) { + + count *= 2; + + } + + return(count); +} + +VOID +HalpEnableEisaInterrupt( + IN ULONG Vector, + IN KINTERRUPT_MODE InterruptMode + ) + +/*++ + +Routine Description: + + This function enables the EISA bus specified EISA bus interrupt and sets + the level/edge register to the requested value. + +Arguments: + + Vector - Supplies the vector of the ESIA interrupt that is enabled. + + InterruptMode - Supplies the mode of the interrupt; LevelSensitive or + Latched. + +Return Value: + + None. + +--*/ + +{ + + // + // Calculate the EISA interrupt vector. + // + + Vector -= EISA_VECTORS; + + // + // Determine if this vector is for interrupt controller 1 or 2. + // + + if (Vector & 0x08) { + + // + // The interrupt is in controller 2. + // + + Vector &= 0x7; + + HalpEisaInterrupt2Mask &= (UCHAR) ~(1 << Vector); + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1, + HalpEisaInterrupt2Mask + ); + + // + // Set the level/edge control register. + // + + if (InterruptMode == LevelSensitive) { + + HalpEisaInterrupt2Level |= (UCHAR) (1 << Vector); + + } else { + + HalpEisaInterrupt2Level &= (UCHAR) ~(1 << Vector); + + } + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2EdgeLevel, + HalpEisaInterrupt2Level + ); + + } else { + + // + // The interrupt is in controller 1. + // + + Vector &= 0x7; + + HalpEisaInterrupt1Mask &= (UCHAR) ~(1 << Vector); + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1, + HalpEisaInterrupt1Mask + ); + + // + // Set the level/edge control register. + // + + if (InterruptMode == LevelSensitive) { + + HalpEisaInterrupt1Level |= (UCHAR) (1 << Vector); + + } else { + + HalpEisaInterrupt1Level &= (UCHAR) ~(1 << Vector); + + } + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1EdgeLevel, + HalpEisaInterrupt1Level + ); + } + +} + +VOID +HalpDisableEisaInterrupt( + IN ULONG Vector + ) + +/*++ + +Routine Description: + + This function Disables the EISA bus specified EISA bus interrupt. + +Arguments: + + Vector - Supplies the vector of the ESIA interrupt that is Disabled. + +Return Value: + + None. + +--*/ + +{ + + + // + // Calculate the EISA interrupt vector. + // + + Vector -= EISA_VECTORS; + + // + // Determine if this vector is for interrupt controller 1 or 2. + // + + if (Vector & 0x08) { + + // + // The interrupt is in controller 2. + // + + Vector &= 0x7; + + HalpEisaInterrupt2Mask |= (UCHAR) 1 << Vector; + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1, + HalpEisaInterrupt2Mask + ); + + } else { + + // + // The interrupt is in controller 1. + // + + Vector &= 0x7; + + HalpEisaInterrupt1Mask |= (ULONG) 1 << Vector; + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1, + HalpEisaInterrupt1Mask + ); + + } + +} + +VOID +HalpEnableOnboardInterrupt( + IN ULONG Vector, + IN KINTERRUPT_MODE InterruptMode + ) + +/*++ + +Routine Description: + + This function enables the ISA bus (onboard) specified ISA bus interrupt and sets + the level/edge register to the requested value. + +Arguments: + + Vector - Supplies the vector of the ISA(onboard) interrupt that is enabled. + + InterruptMode - Supplies the mode of the interrupt; LevelSensitive or + Latched. + +Return Value: + + None. + +--*/ + +{ + + // + // Calculate the ISA interrupt vector. + // + + Vector -= ONBOARD_VECTORS; + + // + // Determine if this vector is for interrupt controller 1 or 2. + // + + if (Vector & 0x08) { + + // + // The interrupt is in controller 2. + // + + Vector &= 0x7; + + HalpOnboardInterrupt2Mask &= (UCHAR) ~(1 << Vector); + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpOnboardControlBase)->Interrupt2ControlPort1, + HalpOnboardInterrupt2Mask + ); + + // + // Set the level/edge control register. + // + + if (InterruptMode == LevelSensitive) { + + HalpOnboardInterrupt2Level |= (UCHAR) (1 << Vector); + + } else { + + HalpOnboardInterrupt2Level &= (UCHAR) ~(1 << Vector); + + } + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpOnboardControlBase)->Interrupt2EdgeLevel, + HalpOnboardInterrupt2Level + ); + + } else { + + // + // The interrupt is in controller 1. + // + + Vector &= 0x7; + + HalpOnboardInterrupt1Mask &= (UCHAR) ~(1 << Vector); + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpOnboardControlBase)->Interrupt1ControlPort1, + HalpOnboardInterrupt1Mask + ); + + // + // Set the level/edge control register. + // + + if (InterruptMode == LevelSensitive) { + + HalpOnboardInterrupt1Level |= (UCHAR) (1 << Vector); + + } else { + + HalpOnboardInterrupt1Level &= (UCHAR) ~(1 << Vector); + + } + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpOnboardControlBase)->Interrupt1EdgeLevel, + HalpOnboardInterrupt1Level + ); + } + +} + +VOID +HalpDisableOnboardInterrupt( + IN ULONG Vector + ) + +/*++ + +Routine Description: + + This function Disables the ISA(Onboard) bus interrupt. + +Arguments: + + Vector - Supplies the vector of the ISA interrupt that is Disabled. + +Return Value: + + None. + +--*/ + +{ + + + // + // Calculate the Onboard interrupt vector. + // + + Vector -= ONBOARD_VECTORS; + + // + // Determine if this vector is for interrupt controller 1 or 2. + // + + if (Vector & 0x08) { + + // + // The interrupt is in controller 2. + // + + Vector &= 0x7; + + HalpOnboardInterrupt2Mask |= (UCHAR) 1 << Vector; + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpOnboardControlBase)->Interrupt2ControlPort1, + HalpOnboardInterrupt2Mask + ); + + } else { + + // + // The interrupt is in controller 1. + // + + Vector &= 0x7; + + HalpOnboardInterrupt1Mask |= (ULONG) 1 << Vector; + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpOnboardControlBase)->Interrupt1ControlPort1, + HalpOnboardInterrupt1Mask + ); + + } + +} + +BOOLEAN +HalpCreateEisaStructures ( + IN INTERFACE_TYPE InterfaceType + ) + +/*++ + +Routine Description: + + This routine initializes the structures necessary for Isa (Desktop onboard) or + EISA operations + and connects the intermediate interrupt dispatcher. It also initializes the + interrupt controller. + +Arguments: + + None. + +Return Value: + + If the second level interrupt dispatcher is connected, then a value of + TRUE is returned. Otherwise, a value of FALSE is returned. + +--*/ + +{ + + UCHAR DataByte; + KIRQL oldIrql; + PEISA_CONTROL controlBase; + + controlBase = (PEISA_CONTROL)HalpOnboardControlBase; + + // + // Raise the IRQL while the interrupt controller is initialized. + // + + KeRaiseIrql(EISA_DEVICE_LEVEL, &oldIrql); + + // + // Initialize the Isa/EISA interrupt controller. There are two cascaded + // interrupt controllers, each of which must initialized with 4 initialize + // control words. + // + + DataByte = 0; + ((PINITIALIZATION_COMMAND_1) &DataByte)->Icw4Needed = 1; + ((PINITIALIZATION_COMMAND_1) &DataByte)->InitializationFlag = 1; + + WRITE_REGISTER_UCHAR( + &(controlBase)->Interrupt1ControlPort0, + DataByte + ); + + WRITE_REGISTER_UCHAR( + &(controlBase)->Interrupt2ControlPort0, + DataByte + ); + + // + // The second intitialization control word sets the interrupt vector to + // 0-15. + // + + DataByte = 0x00; + + WRITE_REGISTER_UCHAR( + &(controlBase)->Interrupt1ControlPort1, + DataByte + ); + + DataByte = 0x08; + + WRITE_REGISTER_UCHAR( + &(controlBase)->Interrupt2ControlPort1, + DataByte + ); + + // + // The third initialization control word set the controls for slave mode. + // The master ICW3 uses bit position and the slave ICW3 uses a numeric. + // + + DataByte = 1 << SLAVE_IRQL_LEVEL; + + WRITE_REGISTER_UCHAR( + &(controlBase)->Interrupt1ControlPort1, + DataByte + ); + + DataByte = SLAVE_IRQL_LEVEL; + + WRITE_REGISTER_UCHAR( + &(controlBase)->Interrupt2ControlPort1, + DataByte + ); + + // + // The fourth initialization control word is used to specify normal + // end-of-interrupt mode and not special-fully-nested mode. + // + + DataByte = 0; + ((PINITIALIZATION_COMMAND_4) &DataByte)->I80x86Mode = 1; + + WRITE_REGISTER_UCHAR( + &(controlBase)->Interrupt1ControlPort1, + DataByte + ); + + WRITE_REGISTER_UCHAR( + &(controlBase)->Interrupt2ControlPort1, + DataByte + ); + + // + // this is for the onboard components + // Disable all of the interrupts except the slave. + // + + HalpOnboardInterrupt1Mask = (UCHAR) ~(1 << SLAVE_IRQL_LEVEL); + + WRITE_REGISTER_UCHAR( + &(controlBase)->Interrupt1ControlPort1, + HalpOnboardInterrupt1Mask + ); + + HalpOnboardInterrupt2Mask = 0xFF; + + WRITE_REGISTER_UCHAR( + &(controlBase)->Interrupt2ControlPort1, + HalpOnboardInterrupt2Mask + ); + + // + // Initialize the edge/level register masks to 0 which is the default + // edge sensitive value. + // + + HalpOnboardInterrupt1Level = 0; + HalpOnboardInterrupt2Level = 0; + + // + // Restore IRQL level. + // + + KeLowerIrql(oldIrql); + + // + // Initialize the DMA mode registers to a default value. + // Disable all of the DMA channels except channel 4 which is that + // cascade of channels 0-3. + // + + WRITE_REGISTER_UCHAR( + &(controlBase)->Dma1BasePort.AllMask, + 0x0F + ); + + WRITE_REGISTER_UCHAR( + &(controlBase)->Dma2BasePort.AllMask, + 0x0E + ); + + return(TRUE); +} + +BOOLEAN +HalpPciEisaDispatch( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ) + +/*++ + +Routine Description: + + This routine is entered as the result of an interrupt being generated + via the vector that is connected to an interrupt object that describes + the EISA device interrupts. Its function is to call the second + level interrupt dispatch routine and acknowledge the interrupt at the EISA + controller. + +Arguments: + + Interrupt - Supplies a pointer to the interrupt object. + + ServiceContext - Supplies a pointer to the EISA interrupt acknowledge + register. + +Return Value: + + Returns the value returned from the second level routine. + +--*/ + +{ + UCHAR interruptVector; + USHORT PCRInOffset, Offset; + BOOLEAN returnValue; + PEISA_CONTROL controlBase; + + // + // this is the default case + // the interrupts occur on the onboard PC core + // + + PCRInOffset = ONBOARD_VECTORS; + Offset = ONBOARD_VECTORS; + controlBase = (PEISA_CONTROL)HalpOnboardControlBase; + + // + // Send a POLL Command to Interrupt Controller 1 + // + + WRITE_REGISTER_UCHAR( + &(controlBase)->Interrupt1ControlPort0, + 0x0c + ); + + // + // Read the interrupt vector + // + + interruptVector = READ_REGISTER_UCHAR( + &(controlBase)->Interrupt1ControlPort0); + + // + // See if there is really an interrupt present + // + + if (interruptVector & 0x80) { + + // + // Strip off the all the bits except for the interrupt vector + // + + interruptVector &= 0x07; + + // + // See if this is an interrupt on IRQ2 which is cascaded to the + // other interrupt controller + // + + if (interruptVector!=0x02) { + + // + // This interrupt is on the first interrupt controller + // + + PCRInOffset += (USHORT)interruptVector; + + // + // Dispatch to the secondary interrupt service routine. + // + + returnValue = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[PCRInOffset])( + PCR->InterruptRoutine[PCRInOffset] + ); + + // + // Clear the interrupt from Interrupt Controller 1 + // + + WRITE_REGISTER_UCHAR( + &(controlBase)->Interrupt1ControlPort0, + NONSPECIFIC_END_OF_INTERRUPT + ); + + return returnValue; + + } else { + + // + // This interrupt is on the second interrupt controller + // + + // + // Send a POLL Command to Interrupt Controller 2 + // + + WRITE_REGISTER_UCHAR( + &(controlBase)->Interrupt2ControlPort0, + 0x0c + ); + + // + // Read the interrupt vector + // + + interruptVector = READ_REGISTER_UCHAR( + &(controlBase)->Interrupt2ControlPort0); + + // + // See if there is really an interrupt present + // + + if (interruptVector & 0x80) { + + // + // Strip off the all the bits except for the interrupt vector + // + + interruptVector &= 0x07; + + PCRInOffset += (USHORT)(interruptVector + 8); + + // + // Dispatch to the secondary interrupt service routine. + // + + returnValue = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[PCRInOffset])( + PCR->InterruptRoutine[PCRInOffset] + ); + + // + // Clear the interrupt from Interrupt Controller 2 + // + + WRITE_REGISTER_UCHAR( + &(controlBase)->Interrupt2ControlPort0, + NONSPECIFIC_END_OF_INTERRUPT + ); + + // + // Clear the interrupt from Interrupt Controller 1 + // + + WRITE_REGISTER_UCHAR( + &(controlBase)->Interrupt1ControlPort0, + NONSPECIFIC_END_OF_INTERRUPT + ); + + return returnValue; + + } + } + } +} + +BOOLEAN +HalpPciEisaSBDispatch( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ) + +/*++ + +Routine Description: + + This routine is entered as the result of an interrupt being generated + via the vector that is connected to an interrupt object that describes + the EISA device interrupts. Its function is to call the second + level interrupt dispatch routine and acknowledge the interrupt at the EISA + controller. + +!!!!!!!!! This routine is only use with the chip 82375 SB (for the moment only PCI Tower) + * Bug : This version doesn't report an interrupt request coming from the slave interrupt controller + * Workaround : + - to detect interrupts from slave controller : + * master controller : read ISR to detect pending interrupt IRQ2 + * if no valid interrupt on master controller --> interrupt from slave controller + - slave controller : Loop until there is no more interrupt valid + +Arguments: + + Interrupt - Supplies a pointer to the interrupt object. + + ServiceContext - Supplies a pointer to the EISA interrupt acknowledge + register. + +Return Value: + + Returns the value returned from the second level routine. + +--*/ + +{ + UCHAR interruptVector = 0; + UCHAR PollSlave; + USHORT PCRInOffset; + BOOLEAN returnValue; + PEISA_CONTROL controlBase; + UCHAR isr; + + + + PCRInOffset = ONBOARD_VECTORS; + controlBase = (PEISA_CONTROL)HalpOnboardControlBase; + + + + // + // Send a POLL Command to Interrupt Controller 1 + // + + WRITE_REGISTER_UCHAR( + &(controlBase)->Interrupt1ControlPort0, + 0x0c + ); + + // + // Read the interrupt vector + // + + interruptVector = READ_REGISTER_UCHAR( + &(controlBase)->Interrupt1ControlPort0); + + // + // See if there is really an interrupt present + // + + if (interruptVector & 0x80) { + + + + // read ISR + + WRITE_REGISTER_UCHAR( + &(controlBase)->Interrupt1ControlPort0, + 0xb + ); + + isr = READ_REGISTER_UCHAR( + &(controlBase)->Interrupt1ControlPort0); + + + if (isr == 0x4) interruptVector = 2; + + + // Strip off the all the bits except for the interrupt vector + // + + interruptVector &= 0x07; + + // + // See if this is an interrupt on IRQ2 which is cascaded to the + // other interrupt controller + // + + if (interruptVector!=0x02) { + + // + // This interrupt is on the first interrupt controller + // + + PCRInOffset += (USHORT)interruptVector; + + + // + // Dispatch to the secondary interrupt service routine. + // + + returnValue = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[PCRInOffset])( + PCR->InterruptRoutine[PCRInOffset] + ); + + WRITE_REGISTER_UCHAR( + &(controlBase)->Interrupt1ControlPort0, + (SPECIFIC_END_OF_INTERRUPT | interruptVector) + ); + return returnValue; + + } + + } + + + + do { + + // + // Send a POLL Command to Interrupt Controller 2 + // + + WRITE_REGISTER_UCHAR( + &(controlBase)->Interrupt2ControlPort0, + 0x0c + ); + + // + // Read the interrupt vector + // + + PollSlave = READ_REGISTER_UCHAR( + &(controlBase)->Interrupt2ControlPort0); + + // + // See if there is really an interrupt present + // + + + + if (PollSlave & 0x80) { + + // + // Strip off the all the bits except for the interrupt vector + // + + interruptVector = PollSlave & 0x07; + + + PCRInOffset = (USHORT)(interruptVector + 8) + ONBOARD_VECTORS; + + + + + // + // Dispatch to the secondary interrupt service routine. + // + + returnValue = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[PCRInOffset])( + PCR->InterruptRoutine[PCRInOffset] + ); + + WRITE_REGISTER_UCHAR( + &(controlBase)->Interrupt2ControlPort0, + (SPECIFIC_END_OF_INTERRUPT | interruptVector) + ); + + + } + + + + } while ( PollSlave & 0x80); + + WRITE_REGISTER_UCHAR( + &(controlBase)->Interrupt1ControlPort0, + (SPECIFIC_END_OF_INTERRUPT | 0x2) + ); + return returnValue; +} + +/*++ + +Routine Description: + + Get the revision ID of the 82374 PCI_EISA Bridge + +Arguments: + + +Return Value: + + Returns the revision of the 82374 PCI_EISA Bridge + +--*/ + + +UCHAR HalpRevIdESC(VOID) +{ +UCHAR save_value,Rev_ID; + +// save value +WRITE_REGISTER_UCHAR(PCI_ESC_ADDR,PCI_ESC_ID_82374); +save_value = READ_REGISTER_UCHAR(PCI_ESC_DATA); + +//free to read +WRITE_REGISTER_UCHAR(PCI_ESC_ADDR,PCI_ESC_ID_82374); +WRITE_REGISTER_UCHAR(PCI_ESC_DATA,0xf); + +//get current version +WRITE_REGISTER_UCHAR(PCI_ESC_ADDR,PCI_REV_ID_82374); +Rev_ID =READ_REGISTER_UCHAR(PCI_ESC_DATA); + +//restore old value +WRITE_REGISTER_UCHAR(PCI_ESC_ADDR,PCI_ESC_ID_82374); +WRITE_REGISTER_UCHAR(PCI_ESC_DATA,save_value); + +return (Rev_ID ); +} diff --git a/private/ntos/nthals/halsnip/mips/jxenvirv.c b/private/ntos/nthals/halsnip/mips/jxenvirv.c new file mode 100644 index 000000000..6584e3a56 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/jxenvirv.c @@ -0,0 +1,192 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/jxenvirv.c,v 1.2 1995/11/02 11:04:33 flo Exp $") + +/*++ + +Copyright (c) 1991 Microsoft Corporation +Copyright (c) 1993 Siemens Nixdorf Informationssyteme AG + +Module Name: + + jxenvirv.c + +Abstract: + + This module implements the HAL get and set environment variable routines + for a MIPS system. + +Environment: + + Kernel mode + +NOTES: + --- Preliminary using ARC function calls --- + +--*/ + + +#include "halp.h" +#include "arccodes.h" +#include "arc.h" + + // preliminary calls to the ARC functions (function vector call) + + /* NOTE: + This is strongly discouraged by the ARC specifications. + Only "reset"/return calls to the prom are recommended. + All other system access to the NVRAM should be handled + by operating systems functions directly. For that the + operating system has to know the algorithms for handling + those data structures (e.g. the checksum calculations). + Though is a drawback in terms of HW/FW-independance NT + seems to avoid side effects of ARC function code that way, + e.g. via register/stack manipulations. + */ + +// +// The following addresses are defined by ARC and handed over to the osloader. +// For now we assume that the osloader will leave this memory part unchanged +// for the operating system (NT), which itself also doesn't overwrite that +// data structure. +// We don't (yet) know yet know whether the firmware copies or maps/banks +// runnable code into the physical memory (or if it just sets up a vector +// into the prom). We also do not know whether the NVRAM variables are copied +// into physical memory or mapped/banked by the (ARC) firmware. +// + +// +// Therefore we preliminary use the ARC entry vectors from ARC.H +// + + +ARC_STATUS +HalGetEnvironmentVariable ( + IN PCHAR Variable, + IN USHORT Length, + OUT PCHAR Buffer + ) + +/*++ + +Routine Description: + + This function locates an environment variable and returns its value. + +Arguments: + + Variable - Supplies a pointer to a zero terminated environment variable + name. + + Length - Supplies the length of the value buffer in bytes. + + Buffer - Supplies a pointer to a buffer that receives the variable value. + +Return Value: + + ESUCCESS is returned if the enviroment variable is located. Otherwise, + ENOENT is returned. + +NOTE: + This implementation returns the error code ENOMEM if the output buffer + is too small. + +--*/ + +{ + + PUCHAR Environment_var; + ULONG Index; + ARC_STATUS Status; + + // + // retrieve the variable + // + + Environment_var = (PUCHAR)ArcGetEnvironmentVariable(Variable); + + if (Environment_var == (PUCHAR)NULL) { + + Status = ENOENT; + + } else { + + // + // Copy the specified value to the output buffer. + // + + for (Index = 0; Index < Length; Index += 1) { + *Buffer = READ_REGISTER_UCHAR(Environment_var); + if (*Buffer == 0) { + break; + } + + Buffer += 1; + Environment_var += 1; + } + + // + // If the length terminated the loop, then return not enough memory. + // Otherwise, return success. + // + + if (Index == Length) { + Status = ENOMEM; + + } else { + Status = ESUCCESS; + } + } + + return Status; +} + +ARC_STATUS +HalSetEnvironmentVariable ( + IN PCHAR Variable, + IN PCHAR Value + ) + +/*++ + +Routine Description: + + This function creates an environment variable with the specified value. + +Arguments: + + Variable - Supplies a pointer to an environment variable name. + + Value - Supplies a pointer to the environment variable value. + +Return Value: + + ESUCCESS is returned if the environment variable is created. Otherwise, + ENOMEM is returned. + +NOTES: + This preliminary implementation always returns ESUCCESS even in case of + error. + +--*/ + +{ + + ARC_STATUS Status; + + Status = ArcSetEnvironmentVariable(Variable, Value); + + switch (Status) { + + case ESUCCESS: + break; + + case ENOSPC: + break; // until further we assume NT can handle that + + case ENOMEM: + default: + Status = ENOMEM; + break; + } + return Status; +} + diff --git a/private/ntos/nthals/halsnip/mips/jxhwsup.c b/private/ntos/nthals/halsnip/mips/jxhwsup.c new file mode 100644 index 000000000..07bd0f121 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/jxhwsup.c @@ -0,0 +1,2250 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/jxhwsup.c,v 1.7 1996/03/12 14:56:20 pierre Exp $") +/*++ + + +Copyright (c) 1989-1993 Microsoft Corporation + +Module Name: + + jxhwsup.c + +Abstract: + + This module contains the IoXxx routines for the NT I/O system that + are hardware dependent. Were these routines not hardware dependent, + they would reside in the iosubs.c module. + + +Environment: + + Kernel mode + ++++*/ + + +#include "halp.h" +#include "eisa.h" + +extern VOID NtClose(); + +typedef struct { + PVOID MmContiguousAddr; + PVOID MmMapIoSpaceAddr; + PVOID Next; +} HALP_MEMORY; + +HALP_MEMORY HalpMemoryBuffer ={0,0,0}, * HalpMemoryBufferPt; + +ULONG +HalpReadEisaData ( + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +// +// Some devices require a phyicially contiguous data buffers for DMA transfers. +// Map registers are used give the appearance that all data buffers are +// contiguous. In order to pool all of the map registers a master +// adapter object is used. This object is allocated and saved internal to this +// file. It contains a bit map for allocation of the registers and a queue +// for requests which are waiting for more map registers. This object is +// allocated during the first request to allocate an adapter which requires +// map registers. +// + +PADAPTER_OBJECT MasterAdapterObject; + + +// +// Map buffer parameters. These are initialized in HalInitSystem +// + + +BOOLEAN +HalpGrowMapBuffers( + PADAPTER_OBJECT AdapterObject, + ULONG Amount + ) +/*++ + +Routine Description: + + This function attempts to allocate additional map buffers for use by I/O + devices. The map register table is updated to indicate the additional + buffers. + This routine is used when the machine is less than 16Mb memory. + +Arguments: + + AdapterObject - Supplies the adapter object for which the buffers are to be + allocated. + + Amount - Indicates the size of the map buffers which should be allocated. + +Return Value: + + TRUE is returned if the memory could be allocated. + + FALSE is returned if the memory could not be allocated. + +--*/ +{ + ULONG MapBufferPhysicalAddress; + PVOID MapBufferVirtualAddress; + PTRANSLATION_ENTRY TranslationEntry; + LONG NumberOfPages; + LONG i; + KIRQL Irql; + PHYSICAL_ADDRESS physicalAddress; + PULONG Page; + PMDL mdl; + + KeAcquireSpinLock( &AdapterObject->SpinLock, &Irql ); + + NumberOfPages = BYTES_TO_PAGES(Amount); + + // + // Make sure there is room for the additional pages. The maximum number of + // slots needed is equal to NumberOfPages + Amount / 64K + 1. + // + + i = BYTES_TO_PAGES(MAXIMUM_MAP_BUFFER_SIZE) - (NumberOfPages + +// (NumberOfPages * PAGE_SIZE) / 0x10000 + + 1 + + AdapterObject->NumberOfMapRegisters); + + if (i < 0) { + + // + // Reduce the allocation amount so it will fit. + // + + NumberOfPages += i; + } + + if (NumberOfPages <= 0) { + // + // No more memory can be allocated. + // + + KeReleaseSpinLock( &AdapterObject->SpinLock, Irql ); + + return(FALSE); + + } + + if (AdapterObject->NumberOfMapRegisters == 0 && HalpMapBufferSize) { + + NumberOfPages = BYTES_TO_PAGES(HalpMapBufferSize); + + // + // Since this is the initial allocation, use the buffer allocated by + // HalInitSystem rather than allocating a new one. + // + + MapBufferPhysicalAddress = HalpMapBufferPhysicalAddress.LowPart; + + // + // Map the buffer for access. + // + + MapBufferVirtualAddress = MmMapIoSpace( + HalpMapBufferPhysicalAddress, + HalpMapBufferSize, + FALSE // Cache disable. Importent for DMA if we + // have more than 16Mb memory in our SNI + ); + + if (MapBufferVirtualAddress == NULL) { + + // + // The buffer could not be mapped. + // + + HalpMapBufferSize = 0; + + KeReleaseSpinLock( &AdapterObject->SpinLock, Irql ); + + + return(FALSE); + } + + } else { + + // + // Allocate the map buffers. + // (We use MmAllocateContiguousMemory because we need a specific physical limit to the address) + // + physicalAddress.LowPart = MAXIMUM_PHYSICAL_ADDRESS - 1; + physicalAddress.HighPart = 0; + MapBufferVirtualAddress = MmAllocateContiguousMemory( + NumberOfPages * PAGE_SIZE, + physicalAddress + ); + + if (MapBufferVirtualAddress == NULL) { + + KeReleaseSpinLock( &AdapterObject->SpinLock, Irql ); + + return(FALSE); + } + + // + // Get the physical address of the map base. + // + + MapBufferPhysicalAddress = MmGetPhysicalAddress( + MapBufferVirtualAddress + ).LowPart; + + // + // flush the new allocated memory area + // because we are going to use it uncached. + // + + mdl = MmCreateMdl(NULL,MapBufferVirtualAddress,NumberOfPages * PAGE_SIZE); + Page = (PULONG) (mdl + 1); + for (i=0;i < NumberOfPages; ++i) { + *Page = (MapBufferPhysicalAddress >> PAGE_SHIFT)+i; + ++Page; + } + KeFlushIoBuffers(mdl,TRUE,TRUE); + + // + // Map registers need to be uncached. + // + + physicalAddress.LowPart = MapBufferPhysicalAddress; + physicalAddress.HighPart = 0; + MapBufferVirtualAddress = MmMapIoSpace( + physicalAddress, + NumberOfPages * PAGE_SIZE, + FALSE + ); + + } + + // + // Initialize the map registers where memory has been allocated. + // + + TranslationEntry = ((PTRANSLATION_ENTRY) AdapterObject->MapRegisterBase) + + AdapterObject->NumberOfMapRegisters; + + // + // Make sure the previous entry is physically contiguous with the next + // entry + // + + if (TranslationEntry != AdapterObject->MapRegisterBase && + (((TranslationEntry - 1)->PhysicalAddress + PAGE_SIZE) != + MapBufferPhysicalAddress ) ){ + + // + // An entry needs to be skipped in the table. This entry will + // remain marked as allocated so that no allocation of map + // registers will cross this boundary. + // + + TranslationEntry++; + AdapterObject->NumberOfMapRegisters++; + } + + for (i = 0; i < NumberOfPages; i++) { + +#if 0 + // + // Make sure the previous entry is physically contiguous with the next + // entry and that a 64K physical boundary is not crossed unless this + // is an Eisa system. + // + + if (TranslationEntry != AdapterObject->MapRegisterBase && + (((TranslationEntry - 1)->PhysicalAddress + PAGE_SIZE) != + MapBufferPhysicalAddress || (!HalpEisaDma && + ((TranslationEntry - 1)->PhysicalAddress & ~0x0ffff) != + (MapBufferPhysicalAddress & ~0x0ffff)))) { + + // + // An entry needs to be skipped in the table. This entry will + // remain marked as allocated so that no allocation of map + // registers will cross this boundary. + // + + TranslationEntry++; + AdapterObject->NumberOfMapRegisters++; + } +#endif + // + // Clear the bits where the memory has been allocated. + // + + RtlClearBits( + AdapterObject->MapRegisters, + TranslationEntry - (PTRANSLATION_ENTRY) + AdapterObject->MapRegisterBase, + 1 + ); + TranslationEntry->VirtualAddress = MapBufferVirtualAddress; + TranslationEntry->PhysicalAddress = MapBufferPhysicalAddress; + TranslationEntry++; + (PCCHAR) MapBufferVirtualAddress += PAGE_SIZE; + MapBufferPhysicalAddress += PAGE_SIZE; + + } + + // + // Remember the number of pages that where allocated. + // + + AdapterObject->NumberOfMapRegisters += NumberOfPages; + + KeReleaseSpinLock( &AdapterObject->SpinLock, Irql ); + + + return(TRUE); +} + +PADAPTER_OBJECT +HalpAllocateAdapter( + IN ULONG MapRegistersPerChannel, + IN PVOID AdapterBaseVa, + IN PVOID ChannelNumber + ) + +/*++ + +Routine Description: + + This routine allocates and initializes an adapter object to represent an + adapter or a DMA controller on the system. If no map registers are required + then a standalone adapter object is allocated with no master adapter. + + If map registers are required, then a master adapter object is used to + allocate the map registers. For Isa systems these registers are really + physically contiguous memory pages. + +Arguments: + + MapRegistersPerChannel - Specifies the number of map registers that each + channel provides for I/O memory mapping. + + AdapterBaseVa - Address of the the DMA controller. + + ChannelNumber - Unused. + +Return Value: + + The function value is a pointer to the allocate adapter object. + +--*/ + +{ + + PADAPTER_OBJECT AdapterObject; + OBJECT_ATTRIBUTES ObjectAttributes; + ULONG Size; + ULONG BitmapSize; + HANDLE Handle; + NTSTATUS Status; + + UNREFERENCED_PARAMETER(ChannelNumber); + + + // + // Initalize the master adapter if necessary. + // + if (MasterAdapterObject == NULL && AdapterBaseVa != (PVOID) -1 && + MapRegistersPerChannel) { + + MasterAdapterObject = HalpAllocateAdapter( + MapRegistersPerChannel, + (PVOID) -1, + NULL + ); + + // + // If we could not allocate the master adapter then give up. + // + if (MasterAdapterObject == NULL) { + + return(NULL); + } + } + + // + // Begin by initializing the object attributes structure to be used when + // creating the adapter object. + // + + InitializeObjectAttributes( &ObjectAttributes, + NULL, + OBJ_PERMANENT, + (HANDLE) NULL, + (PSECURITY_DESCRIPTOR) NULL + ); + + // + // Determine the size of the adapter object. If this is the master object + // then allocate space for the register bit map; otherwise, just allocate + // an adapter object. + // + if (AdapterBaseVa == (PVOID) -1) { + + // + // Allocate a bit map large enough MAXIMUM_MAP_BUFFER_SIZE / PAGE_SIZE + // of map register buffers. + // + + BitmapSize = (((sizeof( RTL_BITMAP ) + + (( ((MAXIMUM_MAP_BUFFER_SIZE*9)/8) / PAGE_SIZE ) + 7 >> 3)) + 3) & ~3); + Size = sizeof( ADAPTER_OBJECT ) + BitmapSize; + + + } else { + + Size = sizeof( ADAPTER_OBJECT ); + + } + + // + // Now create the adapter object. + // + + Status = ObCreateObject( KernelMode, + *IoAdapterObjectType, + &ObjectAttributes, + KernelMode, + (PVOID) NULL, + Size, + 0, + 0, + (PVOID *)&AdapterObject ); + + // + // Reference the object. + // + + if (NT_SUCCESS(Status)) { + + Status = ObReferenceObjectByPointer( + AdapterObject, + FILE_READ_DATA | FILE_WRITE_DATA, + *IoAdapterObjectType, + KernelMode + ); + + } + + // + // If the adapter object was successfully created, then attempt to insert + // it into the the object table. + // + + if (NT_SUCCESS( Status )) { + + Status = ObInsertObject( AdapterObject, + NULL, + FILE_READ_DATA | FILE_WRITE_DATA, + 0, + (PVOID *) NULL, + &Handle ); + + if (NT_SUCCESS( Status )) { + + NtClose( Handle ); + + // + // Initialize the adapter object itself. + // + + AdapterObject->Type = IO_TYPE_ADAPTER; + AdapterObject->Size = (USHORT) Size; + AdapterObject->MapRegistersPerChannel = 1; + AdapterObject->AdapterBaseVa = AdapterBaseVa; + + if (MapRegistersPerChannel) { + + AdapterObject->MasterAdapter = MasterAdapterObject; + + } else { + + AdapterObject->MasterAdapter = NULL; + + } + + // + // Initialize the channel wait queue for this + // adapter. + // + + KeInitializeDeviceQueue( &AdapterObject->ChannelWaitQueue ); + + // + // If this is the MasterAdatper then initialize the register bit map, + // AdapterQueue and the spin lock. + // + + if ( AdapterBaseVa == (PVOID) -1 ) { + + KeInitializeSpinLock( &AdapterObject->SpinLock ); + + InitializeListHead( &AdapterObject->AdapterQueue ); + + AdapterObject->MapRegisters = (PVOID) ( AdapterObject + 1); + + RtlInitializeBitMap( AdapterObject->MapRegisters, + (PULONG) (((PCHAR) (AdapterObject->MapRegisters)) + sizeof( RTL_BITMAP )), + ((9 * MAXIMUM_MAP_BUFFER_SIZE) / 8) / PAGE_SIZE + ); + // + // Set all the bits in the memory to indicate that memory + // has not been allocated for the map buffers + // + + RtlSetAllBits( AdapterObject->MapRegisters ); + AdapterObject->NumberOfMapRegisters = 0; + AdapterObject->CommittedMapRegisters = 0; + + // + // ALlocate the memory map registers. + // + + AdapterObject->MapRegisterBase = ExAllocatePool( + NonPagedPool, + (((9 * MAXIMUM_MAP_BUFFER_SIZE) / 8) / PAGE_SIZE ) * + sizeof(TRANSLATION_ENTRY) + ); + + if (AdapterObject->MapRegisterBase == NULL) { + + ObDereferenceObject( AdapterObject ); + AdapterObject = NULL; + + + return(NULL); + + } + + // + // Zero the map registers. + // + + RtlZeroMemory( + AdapterObject->MapRegisterBase, + (((9 * MAXIMUM_MAP_BUFFER_SIZE) / 8) / PAGE_SIZE ) * + sizeof(TRANSLATION_ENTRY) + ); + + if (!HalpGrowMapBuffers(AdapterObject, INITIAL_MAP_BUFFER_SMALL_SIZE)) + { + + // + // If no map registers could be allocated then free the + // object. + // + + ObDereferenceObject( AdapterObject ); + AdapterObject = NULL; + + + return(NULL); + + } + } + + } else { + + // + // An error was incurred for some reason. Set the return value + // to NULL. + // + + AdapterObject = (PADAPTER_OBJECT) NULL; + } + } else { + + AdapterObject = (PADAPTER_OBJECT) NULL; + + } + + + + return AdapterObject; + +} + +VOID +HalpCopyBufferMap( + IN PMDL Mdl, + IN PTRANSLATION_ENTRY TranslationEntry, + IN PVOID CurrentVa, + IN ULONG Length, + IN BOOLEAN WriteToDevice + ) + +/*++ + +Routine Description: + + This routine copies the specific data between the user's buffer and the + map register buffer. First a the user buffer is mapped if necessary, then + the data is copied. Finally the user buffer will be unmapped if + neccessary. + +Arguments: + + Mdl - Pointer to the MDL that describes the pages of memory that are + being read or written. + + TranslationEntry - The address of the base map register that has been + allocated to the device driver for use in mapping the transfer. + + CurrentVa - Current virtual address in the buffer described by the MDL + that the transfer is being done to or from. + + Length - The length of the transfer. This determines the number of map + registers that need to be written to map the transfer. + + WriteToDevice - Boolean value that indicates whether this is a write + to the device from memory (TRUE), or vice versa. + +Return Value: + + None. + +--*/ +{ + PCCHAR bufferAddress; + PCCHAR mapAddress; + + // + // Get the system address of the MDL. + // + + bufferAddress = MmGetSystemAddressForMdl(Mdl); + + // + // Calculate the actual start of the buffer based on the system VA and + // the current VA. + // + + bufferAddress += (PCCHAR) CurrentVa - (PCCHAR) MmGetMdlVirtualAddress(Mdl); + + mapAddress = (PCCHAR) TranslationEntry->VirtualAddress + + BYTE_OFFSET(CurrentVa); + + // + // Copy the data between the user buffer and map buffer + // + + if (WriteToDevice) { + + RtlMoveMemory( mapAddress, (PCCHAR)bufferAddress, Length); + + } else { + + RtlMoveMemory( (PCCHAR)bufferAddress, mapAddress, Length); + + + } + +} + +PTRANSLATION_ENTRY +HalpAcquireMapBuffers( + ULONG NumberOfMapRegisters, + PADAPTER_OBJECT MasterAdapter) +{ + KIRQL Irql; + ULONG MapRegisterNumber; + PTRANSLATION_ENTRY MapRegisterBase; + + KeAcquireSpinLock( &MasterAdapter->SpinLock, &Irql ); + + MapRegisterNumber = (ULONG)-1; + + MapRegisterNumber = RtlFindClearBitsAndSet( + MasterAdapter->MapRegisters, + NumberOfMapRegisters, + 0 + ); + + if (MapRegisterNumber > MasterAdapter->NumberOfMapRegisters) { + HalpGrowMapBuffers( + MasterAdapterObject, + INCREMENT_MAP_BUFFER_SIZE + ); + MapRegisterNumber = RtlFindClearBitsAndSet( + MasterAdapter->MapRegisters, + NumberOfMapRegisters, + 0 + ); + if (MapRegisterNumber > MasterAdapter->NumberOfMapRegisters) + MapRegisterNumber = (ULONG)-1; + } + + if (MapRegisterNumber == (ULONG)-1) { + + // + // There were not enough free map registers. Queue this request + // on the master adapter where is will wait until some registers + // are deallocated. + // + +// InsertTailList( &MasterAdapter->AdapterQueue, +// &AdapterObject->AdapterQueue +// ); +// Busy = 1; + + MapRegisterBase = NULL; + + } else { + + // + // Calculate the map register base from the allocated map + // register and base of the master adapter object. + // + + MapRegisterBase = ((PTRANSLATION_ENTRY) + MasterAdapter->MapRegisterBase + MapRegisterNumber); + + + } + + KeReleaseSpinLock( &MasterAdapter->SpinLock, Irql ); + + return(MapRegisterBase); +} + + + +PVOID +HalAllocateCommonBuffer( + IN PADAPTER_OBJECT AdapterObject, + IN ULONG Length, + OUT PPHYSICAL_ADDRESS LogicalAddress, + IN BOOLEAN CacheEnabled + ) +/*++ + +Routine Description: + + This function allocates the memory for a common buffer and maps so that it + can be accessed by a master device and the CPU. + +Arguments: + + AdapterObject - Supplies a pointer to the adapter object used by this + device. + + Length - Supplies the length of the common buffer to be allocated. + + LogicalAddress - Returns the logical address of the common buffer. + + CacheEnable - Indicates whether the memeory is cached or not. + +Return Value: + + Returns the virtual address of the common buffer. If the buffer cannot be + allocated then NULL is returned. + +--*/ + +{ + PVOID virtualAddress; + ULONG numberOfMapRegisters; + PTRANSLATION_ENTRY MapRegisterTranslation; + PHYSICAL_ADDRESS physicalAddress; + KIRQL Irql; + + numberOfMapRegisters = BYTES_TO_PAGES(Length); + + // + // Allocate the actual buffer. + // + + if (AdapterObject->InterfaceType != PCIBus) { + + // address < 16Mb (isa compatibility) - cut to 64k + MapRegisterTranslation = HalpAcquireMapBuffers(numberOfMapRegisters,MasterAdapterObject); + if (MapRegisterTranslation == NULL) return(NULL); + virtualAddress = MapRegisterTranslation->VirtualAddress; + LogicalAddress->LowPart = MapRegisterTranslation->PhysicalAddress; + LogicalAddress->HighPart = 0; + + } else { + + // no limitation : address contiguous because we cannot use map registers + // for scatter-gather in this function + physicalAddress.LowPart = 0x7FFFFFFF; + physicalAddress.HighPart = 0; + + virtualAddress = MmAllocateContiguousMemory( + Length, + physicalAddress + ); + + if (virtualAddress == NULL) { + return(NULL); + } + + *LogicalAddress = MmGetPhysicalAddress(virtualAddress); + + if (CacheEnabled == FALSE) { + PULONG Page; + ULONG i; + PMDL mdl; + + // + // flush the new allocated memory area + // because we are going to use it uncached. + // + + mdl = MmCreateMdl(NULL,virtualAddress,Length); + Page = (PULONG) (mdl + 1); + for (i=0;i < numberOfMapRegisters; ++i) { + *Page = (((LogicalAddress->LowPart)) >> PAGE_SHIFT)+i; + ++Page; + } + KeFlushIoBuffers(mdl,TRUE,TRUE); + + // save the allocated address to be able to free it later. + + KeAcquireSpinLock(&HalpMemoryBufferLock,&Irql); + HalpMemoryBufferPt = &HalpMemoryBuffer; + while (HalpMemoryBufferPt->Next) HalpMemoryBufferPt = HalpMemoryBufferPt->Next; + HalpMemoryBufferPt->Next = ExAllocatePool(PagedPool,sizeof(HALP_MEMORY)); + HalpMemoryBufferPt = HalpMemoryBufferPt->Next; + HalpMemoryBufferPt->Next = NULL; + HalpMemoryBufferPt->MmContiguousAddr = virtualAddress; + + // second mapping to get uncached addresses... + virtualAddress = MmMapIoSpace( + *LogicalAddress, + Length, + FALSE + ); + + HalpMemoryBufferPt->MmMapIoSpaceAddr = virtualAddress; + KeReleaseSpinLock(&HalpMemoryBufferLock,Irql); + } + } +// KeStallExecutionProcessor(50000); + return(virtualAddress); +} + +BOOLEAN +HalFlushCommonBuffer( + IN PADAPTER_OBJECT AdapterObject, + IN ULONG Length, + IN PHYSICAL_ADDRESS LogicalAddress, + IN PVOID VirtualAddress + ) +/*++ + +Routine Description: + + This function is called to flush any hardware adapter buffers when the + driver needs to read data written by an I/O master device to a common + buffer. + +Arguments: + + AdapterObject - Supplies a pointer to the adapter object used by this + device. + + Length - Supplies the length of the common buffer. This should be the same + value used for the allocation of the buffer. + + LogicalAddress - Supplies the logical address of the common buffer. This + must be the same value return by HalAllocateCommonBuffer. + + VirtualAddress - Supplies the virtual address of the common buffer. This + must be the same value return by HalAllocateCommonBuffer. + +Return Value: + + Returns TRUE if no errors were detected; otherwise, FALSE is return. + +--*/ + +{ + + return(TRUE); + +} + +VOID +HalFreeCommonBuffer( + IN PADAPTER_OBJECT AdapterObject, + IN ULONG Length, + IN PHYSICAL_ADDRESS LogicalAddress, + IN PVOID VirtualAddress, + IN BOOLEAN CacheEnabled + ) +/*++ + +Routine Description: + + This function frees a common buffer and all of the resouces it uses. + +Arguments: + + AdapterObject - Supplies a pointer to the adapter object used by this + device. + + Length - Supplies the length of the common buffer. This should be the same + value used for the allocation of the buffer. + + LogicalAddress - Supplies the logical address of the common buffer. This + must be the same value return by HalAllocateCommonBuffer. + + VirtualAddress - Supplies the virtual address of the common buffer. This + must be the same value return by HalAllocateCommonBuffer. + + CacheEnable - Indicates whether the memeory is cached or not. + +Return Value: + + None + +--*/ + +{ + PTRANSLATION_ENTRY mapRegisterBase,resultat; + ULONG numberOfMapRegisters; +// ULONG mapRegisterNumber; + ULONG i; + HALP_MEMORY * HalpMemoryPrevious; + KIRQL Irql; + + // + // Free the memory for the common buffer. + // + + if (AdapterObject->InterfaceType == PCIBus) { + + if (CacheEnabled == FALSE) { + + KeAcquireSpinLock(&HalpMemoryBufferLock ,&Irql); + HalpMemoryPrevious = HalpMemoryBufferPt = &HalpMemoryBuffer; + while (HalpMemoryBufferPt) { + if (HalpMemoryBufferPt->MmMapIoSpaceAddr == VirtualAddress) { + MmUnmapIoSpace(VirtualAddress, Length); + MmFreeContiguousMemory(HalpMemoryBufferPt->MmContiguousAddr); + HalpMemoryPrevious->Next = HalpMemoryBufferPt->Next; + ExFreePool(HalpMemoryBufferPt); + KeReleaseSpinLock(&HalpMemoryBufferLock,Irql); + return; + } + HalpMemoryPrevious = HalpMemoryBufferPt; + HalpMemoryBufferPt = HalpMemoryBufferPt->Next; + } + KeReleaseSpinLock(&HalpMemoryBufferLock,Irql); + + } else MmFreeContiguousMemory(VirtualAddress); + + return; + + } + + + // + // Calculate the number of map registers, the map register number and + // the map register base. + // + + numberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(VirtualAddress, Length); + // mapRegisterNumber = LogicalAddress.LowPart >> PAGE_SHIFT; + mapRegisterBase = (PTRANSLATION_ENTRY) MasterAdapterObject->MapRegisterBase; + resultat = NULL; + + for (i = 0; i < MasterAdapterObject->NumberOfMapRegisters; i++) { + + if (mapRegisterBase->VirtualAddress == VirtualAddress) { + resultat = mapRegisterBase; + break; + } + + mapRegisterBase++; + + } + + + // + // Free the map registers. + // + + IoFreeMapRegisters( + AdapterObject, + (PVOID) resultat, + numberOfMapRegisters + ); + + return; +} + +PVOID +HalAllocateCrashDumpRegisters( + IN PADAPTER_OBJECT AdapterObject, + IN PULONG NumberOfMapRegisters + ) +/*++ + +Routine Description: + + This routine is called during the crash dump disk driver's initialization + to allocate a number map registers permanently. + +Arguments: + + AdapterObject - Pointer to the adapter control object to allocate to the + driver. + NumberOfMapRegisters - Number of map registers requested and update to show + number actually allocated. + +Return Value: + + Returns STATUS_SUCESS if map registers allocated. + +--*/ + +{ + PADAPTER_OBJECT MasterAdapter; + ULONG MapRegisterNumber; + + // + // Begin by obtaining a pointer to the master adapter associated with this + // request. + // + + MasterAdapter = AdapterObject->MasterAdapter; + + // + // Check to see whether this driver needs to allocate any map registers. + // + + if (AdapterObject->NeedsMapRegisters) { + + // + // Ensure that this adapter has enough total map registers to satisfy + // the request. + // + + if (*NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel) { + AdapterObject->NumberOfMapRegisters = 0; + return NULL; + } + + // + // Attempt to allocate the required number of map registers w/o + // affecting those registers that were allocated when the system + // crashed. + // + + MapRegisterNumber = (ULONG)-1; + + MapRegisterNumber = RtlFindClearBitsAndSet( + MasterAdapter->MapRegisters, + *NumberOfMapRegisters, + 0 + ); + + if (MapRegisterNumber == (ULONG)-1) { + + // + // Not enough free map registers were found, so they were busy + // being used by the system when it crashed. Force the appropriate + // number to be "allocated" at the base by simply overjamming the + // bits and return the base map register as the start. + // + + RtlSetBits( + MasterAdapter->MapRegisters, + 0, + *NumberOfMapRegisters + ); + MapRegisterNumber = 0; + + } + + // + // Calculate the map register base from the allocated map + // register and base of the master adapter object. + // + + AdapterObject->MapRegisterBase = ((PTRANSLATION_ENTRY) + MasterAdapter->MapRegisterBase + MapRegisterNumber); + + // + // Set the no scatter/gather flag if scatter/gather not + // supported. + // + + if (!AdapterObject->ScatterGather) { + + AdapterObject->MapRegisterBase = (PVOID) + ((ULONG) AdapterObject->MapRegisterBase | NO_SCATTER_GATHER); + + } + + } else { + + AdapterObject->MapRegisterBase = NULL; + AdapterObject->NumberOfMapRegisters = 0; + } + + return AdapterObject->MapRegisterBase; +} + +VOID +IoFreeAdapterChannel( + IN PADAPTER_OBJECT AdapterObject + ) + +/*++ + +Routine Description: + + This routine is invoked to deallocate the specified adapter object. + Any map registers that were allocated are also automatically deallocated. + No checks are made to ensure that the adapter is really allocated to + a device object. However, if it is not, then kernel will bugcheck. + + If another device is waiting in the queue to allocate the adapter object + it will be pulled from the queue and its execution routine will be + invoked. + +Arguments: + + AdapterObject - Pointer to the adapter object to be deallocated. + +Return Value: + + None. + +--*/ + +{ + PKDEVICE_QUEUE_ENTRY Packet; + PWAIT_CONTEXT_BLOCK Wcb; + PADAPTER_OBJECT MasterAdapter; + BOOLEAN Busy = FALSE; + IO_ALLOCATION_ACTION Action; + KIRQL Irql; + LONG MapRegisterNumber; + + + // + // Begin by getting the address of the master adapter. + // + + MasterAdapter = AdapterObject->MasterAdapter; + + // + // Pull requests of the adapter's device wait queue as long as the + // adapter is free and there are sufficient map registers available. + // + + while( TRUE ) { + + // + // Begin by checking to see whether there are any map registers that + // need to be deallocated. If so, then deallocate them now. + // + + if (AdapterObject->NumberOfMapRegisters != 0) { + IoFreeMapRegisters( AdapterObject, + AdapterObject->MapRegisterBase, + AdapterObject->NumberOfMapRegisters + ); + } + + // + // Simply remove the next entry from the adapter's device wait queue. + // If one was successfully removed, allocate any map registers that it + // requires and invoke its execution routine. + // + + Packet = KeRemoveDeviceQueue( &AdapterObject->ChannelWaitQueue ); + if (Packet == NULL) { + + // + // There are no more requests break out of the loop. + // + + break; + } + + Wcb = CONTAINING_RECORD( Packet, + WAIT_CONTEXT_BLOCK, + WaitQueueEntry ); + + AdapterObject->CurrentWcb = Wcb; + AdapterObject->NumberOfMapRegisters = Wcb->NumberOfMapRegisters; + + // + // Check to see whether this driver wishes to allocate any map + // registers. If so, then queue the device object to the master + // adapter queue to wait for them to become available. If the driver + // wants map registers, ensure that this adapter has enough total + // map registers to satisfy the request. + // + + if (Wcb->NumberOfMapRegisters != 0 && + AdapterObject->MasterAdapter != NULL) { + + // + // Lock the map register bit map and the adapter queue in the + // master adapter object. The channel structure offset is used as + // a hint for the register search. + // + + KeAcquireSpinLock( &MasterAdapter->SpinLock, &Irql ); + + MapRegisterNumber = -1; + + if (IsListEmpty( &MasterAdapter->AdapterQueue)) { + MapRegisterNumber = RtlFindClearBitsAndSet( + MasterAdapter->MapRegisters, + Wcb->NumberOfMapRegisters, + 0); + } + if (MapRegisterNumber == -1) { + + // + // There were not enough free map registers. Queue this request + // on the master adapter where is will wait until some registers + // are deallocated. + // + + InsertTailList( &MasterAdapter->AdapterQueue, + &AdapterObject->AdapterQueue + ); + Busy = 1; + + } else { + + AdapterObject->MapRegisterBase = (PVOID)((PTRANSLATION_ENTRY) + MasterAdapter->MapRegisterBase + MapRegisterNumber); + + // + // Set the no scatter/gather flag if scatter/gather not + // supported. + // + + if (!AdapterObject->ScatterGather) { + + AdapterObject->MapRegisterBase = (PVOID) + ((ULONG)AdapterObject->MapRegisterBase |NO_SCATTER_GATHER); + + } + } + + KeReleaseSpinLock( &MasterAdapter->SpinLock, Irql ); + + } else { + + AdapterObject->MapRegisterBase = NULL; + AdapterObject->NumberOfMapRegisters = 0; + + } + + // + // If there were either enough map registers available or no map + // registers needed to be allocated, invoke the driver's execution + // routine now. + // + + if (!Busy) { + AdapterObject->CurrentWcb = Wcb; + Action = Wcb->DeviceRoutine( Wcb->DeviceObject, + Wcb->CurrentIrp, + AdapterObject->MapRegisterBase, + Wcb->DeviceContext ); + + // + // If the execution routine would like to have the adapter + // deallocated, then release the adapter object. + // + + if (Action == KeepObject) { + + // + // This request wants to keep the channel a while so break + // out of the loop. + // + + break; + + } + + // + // If the driver wants to keep the map registers then set the + // number allocated to 0. This keeps the deallocation routine + // from deallocating them. + // + + if (Action == DeallocateObjectKeepRegisters) { + AdapterObject->NumberOfMapRegisters = 0; + } + + } else { + + // + // This request did not get the requested number of map registers so + // out of the loop. + // + + break; + } + } + +} + +VOID +IoFreeMapRegisters( + PADAPTER_OBJECT AdapterObject, + PVOID MapRegisterBase, + ULONG NumberOfMapRegisters + ) +/*++ + +Routine Description: + + This routine deallocates the map registers for the adapter. If there are + any queued adapter waiting for an attempt is made to allocate the next + entry. + +Arguments: + + AdapterObject - The adapter object to where the map register should be + returned. + + MapRegisterBase - The map register base of the registers to be deallocated. + + NumberOfMapRegisters - The number of registers to be deallocated. + +Return Value: + + None + +--+*/ +{ + PADAPTER_OBJECT MasterAdapter; + LONG MapRegisterNumber; + PWAIT_CONTEXT_BLOCK Wcb; + PLIST_ENTRY Packet; + IO_ALLOCATION_ACTION Action; + KIRQL Irql; + + + // + // Begin by getting the address of the master adapter. + // + + if (AdapterObject->MasterAdapter != NULL && MapRegisterBase != NULL) { + + MasterAdapter = AdapterObject->MasterAdapter; + + } else { + + // + // There are no map registers to return. + // + + return; + } + + // + // Strip no scatter/gather flag. + // + + MapRegisterBase = (PVOID) ((ULONG) MapRegisterBase & ~NO_SCATTER_GATHER); + + MapRegisterNumber = (PTRANSLATION_ENTRY) MapRegisterBase - + (PTRANSLATION_ENTRY) MasterAdapter->MapRegisterBase; + + // + // Acquire the master adapter spinlock which locks the adapter queue and the + // bit map for the map registers. + // + + KeAcquireSpinLock(&MasterAdapter->SpinLock, &Irql); + + // + // Return the registers to the bit map. + // + + RtlClearBits( MasterAdapter->MapRegisters, + MapRegisterNumber, + NumberOfMapRegisters + ); + + // + // Process any requests waiting for map registers in the adapter queue. + // Requests are processed until a request cannot be satisfied or until + // there are no more requests in the queue. + // + + while(TRUE) { + + if ( IsListEmpty(&MasterAdapter->AdapterQueue) ){ + break; + } + + Packet = RemoveHeadList( &MasterAdapter->AdapterQueue ); + AdapterObject = CONTAINING_RECORD( Packet, + ADAPTER_OBJECT, + AdapterQueue + ); + Wcb = AdapterObject->CurrentWcb; + + // + // Attempt to allocate map registers for this request. Use the previous + // register base as a hint. + // + + MapRegisterNumber = RtlFindClearBitsAndSet( MasterAdapter->MapRegisters, + AdapterObject->NumberOfMapRegisters, + MasterAdapter->NumberOfMapRegisters + ); + + if (MapRegisterNumber == -1) { + + // + // There were not enough free map registers. Put this request back on + // the adapter queue where is came from. + // + + InsertHeadList( &MasterAdapter->AdapterQueue, + &AdapterObject->AdapterQueue + ); + + break; + + } + + KeReleaseSpinLock( &MasterAdapter->SpinLock, Irql ); + + AdapterObject->MapRegisterBase = (PVOID) ((PTRANSLATION_ENTRY) + MasterAdapter->MapRegisterBase + MapRegisterNumber); + + // + // Set the no scatter/gather flag if scatter/gather not + // supported. + // + + if (!AdapterObject->ScatterGather) { + + AdapterObject->MapRegisterBase = (PVOID) + ((ULONG) AdapterObject->MapRegisterBase | NO_SCATTER_GATHER); + + } + // + // Invoke the driver's execution routine now. + // + + Action = Wcb->DeviceRoutine( Wcb->DeviceObject, + Wcb->CurrentIrp, + AdapterObject->MapRegisterBase, + Wcb->DeviceContext ); + + // + // If the driver wishes to keep the map registers then set the number + // allocated to zero and set the action to deallocate object. + // + + if (Action == DeallocateObjectKeepRegisters) { + AdapterObject->NumberOfMapRegisters = 0; + Action = DeallocateObject; + } + + // + // If the driver would like to have the adapter deallocated, + // then deallocate any map registers allocated and then release + // the adapter object. + // + + if (Action == DeallocateObject) { + + // + // The map registers registers are deallocated here rather than in + // IoFreeAdapterChannel. This limits the number of times + // this routine can be called recursively possibly overflowing + // the stack. The worst case occurs if there is a pending + // request for the adapter that uses map registers and whos + // excution routine decallocates the adapter. In that case if + // there are no requests in the master adapter queue, then + // IoFreeMapRegisters will get called again. + // + + if (AdapterObject->NumberOfMapRegisters != 0) { + + // + // Deallocate the map registers and clear the count so that + // IoFreeAdapterChannel will not deallocate them again. + // + + KeAcquireSpinLock( &MasterAdapter->SpinLock, &Irql ); + + RtlClearBits( MasterAdapter->MapRegisters, + MapRegisterNumber, + AdapterObject->NumberOfMapRegisters + ); + + AdapterObject->NumberOfMapRegisters = 0; + + KeReleaseSpinLock( &MasterAdapter->SpinLock, Irql ); + } + + IoFreeAdapterChannel( AdapterObject ); + } + + KeAcquireSpinLock( &MasterAdapter->SpinLock, &Irql ); + + } + + KeReleaseSpinLock( &MasterAdapter->SpinLock, Irql ); + + +} + +BOOLEAN +HalTranslateBusAddress( + IN INTERFACE_TYPE InterfaceType, + IN ULONG BusNumber, + IN PHYSICAL_ADDRESS BusAddress, + IN OUT PULONG AddressSpace, + OUT PPHYSICAL_ADDRESS TranslatedAddress + ) + +/*++ + +Routine Description: + + This function returns the system physical address for a specified I/O bus + address. The return value is suitable for use in a subsequent call to + MmMapIoSpace. + +Arguments: + + InterfaceType - Supplies the type of bus which the address is for. + + BusNumber - Supplies the bus number for the device. + + BusAddress - Supplies the bus relative address. + + AddressSpace - Supplies the address space number for the device: 0 for + memory and 1 for I/O space. Returns the address space on this system. + + 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 + +--*/ + +{ + + // + // SNI only has one I/O bus which is an EISA, so the bus number is unused. + // + + UNREFERENCED_PARAMETER( BusNumber ); + + + TranslatedAddress->HighPart = 0; + + // + // If this is for the internal bus then just return the passed parameter. + // + + if (InterfaceType == Internal) { + + // + // There is no difference between IoSpace and MemorySpace in the internal Interface. + // Mips Processors have only memory mapped I/O + // + + *AddressSpace = 0; + + // + // Return the passed parameters. + // + + TranslatedAddress->LowPart = BusAddress.LowPart; + + return(TRUE); + } + + if (InterfaceType == PCIBus) { + + // + // Return the passed parameters. + // + + if (*AddressSpace == 1) { + + // + // PCI IO Space + // + + TranslatedAddress->LowPart = BusAddress.LowPart | PCI_IO_PHYSICAL_BASE; + + } else { + + TranslatedAddress->LowPart = BusAddress.LowPart | PCI_MEMORY_BELOW1M_PHYSICAL_BASE; + + } + + *AddressSpace = 0; + + return (TRUE); + } + + + if (InterfaceType != Isa && InterfaceType != Eisa) { + + DebugPrint(("HAL: HalTranslateBusAddress: WRONG INTERFACE (%d) ", InterfaceType)); + + // + // Not on this system -- return nothing. + // + + *AddressSpace = 0; + TranslatedAddress->LowPart = 0; + return(FALSE); + } + + // + // Determine the address based on whether the bus address is in I/O space + // or bus memory space. + // + + if (*AddressSpace) { + + // + // The address is in I/O space. + // we always direct Isa and Eisa Adresses to the extension board + // + + *AddressSpace = 0; + + TranslatedAddress->LowPart = BusAddress.LowPart | + EISA_CONTROL_PHYSICAL_BASE; + + if (TranslatedAddress->LowPart < BusAddress.LowPart) { + + // + // A carry occurred. + // + + TranslatedAddress->HighPart = 1; + } + return(TRUE); + + } else { + + // + // The address is in memory space. + // we always direct Isa and Eisa Adresses to the extension board + // + + *AddressSpace = 0; + + TranslatedAddress->LowPart = BusAddress.LowPart | + EISA_MEMORY_PHYSICAL_BASE; + + if (TranslatedAddress->LowPart < BusAddress.LowPart) { + + // + // A carry occurred. + // + + TranslatedAddress->HighPart = 1; + } + + return(TRUE); + + } + + DebugPrint(("HAL: HalTranslateBusAddress: Beeing in the very bad tree\n")); + + TranslatedAddress->LowPart = BusAddress.LowPart; + TranslatedAddress->HighPart = 0; + return(FALSE); +} + +ULONG +HalGetBusDataByOffset( + IN BUS_DATA_TYPE BusDataType, + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ) +/*++ + +Routine Description: + + The function returns the bus data for a slot or address. + +Arguments: + + BusDataType - Supplies the type of bus. + + BusNumber - Indicates which bus. + + Buffer - Supplies the space to store the data. + + Offset - Offset in the BusData buffer + + Length - Supplies a count in bytes of the maximum amount to return. + +Return Value: + + Returns the amount of data stored into the buffer. + +--*/ + +{ + + ULONG DataLength = 0; + + switch (BusDataType) { + + case PCIConfiguration: + DataLength = HalpGetPCIData(BusNumber, SlotNumber, Buffer, Offset, Length); + break; + + case EisaConfiguration: + DataLength = HalpReadEisaData(BusNumber, SlotNumber, Buffer, Offset, Length); + break; + } + + return(DataLength); + +} + +ULONG +HalGetBusData( + IN BUS_DATA_TYPE BusDataType, + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Length + ) +/*++ + +Routine Description: + + Subset of HalGetBusDataByOffset, just pass the request along. + +--*/ +{ + return HalGetBusDataByOffset ( + BusDataType, + BusNumber, + SlotNumber, + Buffer, + 0, + Length + ); +} + +ULONG +HalSetBusDataByOffset( + IN BUS_DATA_TYPE BusDataType, + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ) +/*++ + +Routine Description: + + The function sets the bus data for a slot or address. + +Arguments: + + BusDataType - Supplies the type of bus. + + BusNumber - Indicates which bus. + + Buffer - Supplies the space to store the data. + + Offset - Offset in the BusData buffer + + Length - Supplies a count in bytes of the maximum amount to return. + +Return Value: + + Returns the amount of data stored into the buffer. + +--*/ + +{ + + ULONG DataLength = 0; + + + switch (BusDataType) { + + case PCIConfiguration: + DataLength = HalpSetPCIData(BusNumber, SlotNumber, Buffer, Offset, Length); + break; + + default: + break; + + } + + return(DataLength); +} + +ULONG +HalSetBusData( + IN BUS_DATA_TYPE BusDataType, + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Length + ) +/*++ + +Routine Description: + + Subset of HalGetBusDataByOffset, just pass the request along. + +--*/ +{ + return HalSetBusDataByOffset( + BusDataType, + BusNumber, + SlotNumber, + Buffer, + 0, + Length + ); +} + +NTSTATUS +HalAssignSlotResources ( + IN PUNICODE_STRING RegistryPath, + IN PUNICODE_STRING DriverClassName OPTIONAL, + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT DeviceObject OPTIONAL, + IN INTERFACE_TYPE BusType, + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN OUT PCM_RESOURCE_LIST *AllocatedResources + ) +/*++ + +Routine Description: + + Reads the targeted device to determine it's required resources. + Calls IoAssignResources to allocate them. + Sets the targeted device with it's assigned resoruces + and returns the assignments to the caller. + +Arguments: + + RegistryPath - Passed to IoAssignResources. + A device specific registry path in the current-control-set, used + to check for pre-assigned settings and to track various resource + assignment information for this device. + + DriverClassName Used to report the assigned resources for the driver/device + DriverObject - Used to report the assigned resources for the driver/device + DeviceObject - Used to report the assigned resources for the driver/device + (ie, IoReportResoruceUsage) + BusType + BusNumber + SlotNumber - Together BusType,BusNumber,SlotNumber uniquely + indentify the device to be queried & set. + +Return Value: + + STATUS_SUCCESS or error + +--*/ +{ + switch (BusType) { + + case PCIBus: + + return HalpAssignPCISlotResources (BusNumber, + RegistryPath, + DriverClassName, + DriverObject, + DeviceObject, + SlotNumber, + AllocatedResources); + break; + + default: + return STATUS_NOT_SUPPORTED; + break; + + } +} + +NTSTATUS +HalAdjustResourceList ( + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList + ) +/*++ + +Routine Description: + + Takes the pResourceList and limits any requested resource to + it's corrisponding bus requirements. + +Arguments: + + pResourceList - The resource list to adjust. + +Return Value: + + STATUS_SUCCESS or error + +--*/ +{ + if ((*pResourceList)->InterfaceType == PCIBus) + return HalpAdjustPCIResourceList ((*pResourceList)->BusNumber, pResourceList); + + // + // BUGBUG: This function should verify that the resoruces fit + // the bus requirements - for now we will assume that the bus + // can support anything the device may ask for. + // + + return STATUS_SUCCESS; +} + +ULONG +HalpReadEisaData ( + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ) +/*++ + +Routine Description: + + The function returns the Eisa bus data for a slot or address. + +Arguments: + + BusDataType - Supplies the type of bus. + + BusNumber - Indicates which bus. + + Buffer - Supplies the space to store the data. + + Length - Supplies a count in bytes of the maximum amount to return. + +Return Value: + + Returns the amount of data stored into the buffer. + +--*/ + +{ + OBJECT_ATTRIBUTES ObjectAttributes; + OBJECT_ATTRIBUTES BusObjectAttributes; + PWSTR EisaPath = L"\\Registry\\Machine\\Hardware\\Description\\System\\EisaAdapter"; + PWSTR ConfigData = L"Configuration Data"; + ANSI_STRING TmpString; + UCHAR BusString[] = "00"; + UNICODE_STRING RootName, BusName; + UNICODE_STRING ConfigDataName; + NTSTATUS NtStatus; + PKEY_VALUE_FULL_INFORMATION ValueInformation; + PCM_FULL_RESOURCE_DESCRIPTOR Descriptor; + PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialResource; + PCM_EISA_SLOT_INFORMATION SlotInformation; + ULONG PartialCount; + ULONG TotalDataSize, SlotDataSize; + HANDLE EisaHandle, BusHandle; + ULONG BytesWritten, BytesNeeded; + PUCHAR KeyValueBuffer; + ULONG i; + ULONG DataLength = 0; + PUCHAR DataBuffer = Buffer; + BOOLEAN Found = FALSE; + + + RtlInitUnicodeString( + &RootName, + EisaPath + ); + + InitializeObjectAttributes( + &ObjectAttributes, + &RootName, + OBJ_CASE_INSENSITIVE, + (HANDLE)NULL, + NULL + ); + + // + // Open the EISA root + // + + NtStatus = ZwOpenKey( + &EisaHandle, + KEY_READ, + &ObjectAttributes + ); + + if (!NT_SUCCESS(NtStatus)) { + KdPrint(("HAL: Open Status = %x\n",NtStatus)); + return(0); + } + + // + // Init bus number path + // + + if (BusNumber > 99) { + return (0); + } + + if (BusNumber > 9) { + BusString[0] += (UCHAR) (BusNumber/10); + BusString[1] += (UCHAR) (BusNumber % 10); + } else { + BusString[0] += (UCHAR) BusNumber; + BusString[1] = '\0'; + } + + RtlInitAnsiString( + &TmpString, + BusString + ); + + RtlAnsiStringToUnicodeString( + &BusName, + &TmpString, + TRUE + ); + + + InitializeObjectAttributes( + &BusObjectAttributes, + &BusName, + OBJ_CASE_INSENSITIVE, + (HANDLE)EisaHandle, + NULL + ); + + // + // Open the EISA root + Bus Number + // + + NtStatus = ZwOpenKey( + &BusHandle, + KEY_READ, + &BusObjectAttributes + ); + + if (!NT_SUCCESS(NtStatus)) { + KdPrint(("HAL: Opening Bus Number: Status = %x\n",NtStatus)); + return(0); + } + + // + // opening the configuration data. This first call tells us how + // much memory we need to allocate + // + + RtlInitUnicodeString( + &ConfigDataName, + ConfigData + ); + + // + // This should fail. We need to make this call so we can + // get the actual size of the buffer to allocate. + // + + NtStatus = ZwQueryValueKey( + BusHandle, + &ConfigDataName, + KeyValueFullInformation, + ValueInformation, + 0, + &BytesNeeded + ); + + KeyValueBuffer = ExAllocatePool( + NonPagedPool, + BytesNeeded + ); + + if (KeyValueBuffer == NULL) { + KdPrint(("HAL: Cannot allocate Key Value Buffer\n")); + ZwClose(BusHandle); + return(0); + } + + ValueInformation = (PKEY_VALUE_FULL_INFORMATION)KeyValueBuffer; + + NtStatus = ZwQueryValueKey( + BusHandle, + &ConfigDataName, + KeyValueFullInformation, + ValueInformation, + BytesNeeded, + &BytesWritten + ); + + + ZwClose(BusHandle); + + if (!NT_SUCCESS(NtStatus) || ValueInformation->DataLength == 0) { + KdPrint(("HAL: Query Config Data: Status = %x\n",NtStatus)); + ExFreePool(KeyValueBuffer); + return(0); + } + + + // + // We get back a Full Resource Descriptor List + // + + Descriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PUCHAR)ValueInformation + + ValueInformation->DataOffset); + + PartialResource = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) + &(Descriptor->PartialResourceList.PartialDescriptors); + PartialCount = Descriptor->PartialResourceList.Count; + + for (i = 0; i < PartialCount; i++) { + + // + // Do each partial Resource + // + + switch (PartialResource->Type) { + case CmResourceTypeNull: + case CmResourceTypePort: + case CmResourceTypeInterrupt: + case CmResourceTypeMemory: + case CmResourceTypeDma: + + // + // We dont care about these. + // + + PartialResource++; + + break; + + case CmResourceTypeDeviceSpecific: + + // + // Bingo! + // + + TotalDataSize = PartialResource->u.DeviceSpecificData.DataSize; + + SlotInformation = (PCM_EISA_SLOT_INFORMATION) + ((PUCHAR)PartialResource + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)); + + while (((LONG)TotalDataSize) > 0) { + + if (SlotInformation->ReturnCode == EISA_EMPTY_SLOT) { + + SlotDataSize = sizeof(CM_EISA_SLOT_INFORMATION); + + } else { + + SlotDataSize = sizeof(CM_EISA_SLOT_INFORMATION) + + SlotInformation->NumberFunctions * + sizeof(CM_EISA_FUNCTION_INFORMATION); + } + + if (SlotDataSize > TotalDataSize) { + + // + // Something is wrong again + // + + ExFreePool(KeyValueBuffer); + return(0); + + } + + if (SlotNumber != 0) { + + SlotNumber--; + + SlotInformation = (PCM_EISA_SLOT_INFORMATION) + ((PUCHAR)SlotInformation + SlotDataSize); + + TotalDataSize -= SlotDataSize; + + continue; + + } + + // + // This is our slot + // + + Found = TRUE; + break; + + } + + // + // End loop + // + + i = PartialCount; + + break; + + default: + KdPrint(("Bad Data in registry!\n")); + ExFreePool(KeyValueBuffer); + return(0); + } + } + + if (Found) { + + i = Length + Offset; + if (i > SlotDataSize) { + i = SlotDataSize; + } + + DataLength = i - Offset; + RtlMoveMemory (Buffer, ((PUCHAR)SlotInformation + Offset), DataLength); + + } + + ExFreePool(KeyValueBuffer); + return DataLength; +} + diff --git a/private/ntos/nthals/halsnip/mips/jxmapio.c b/private/ntos/nthals/halsnip/mips/jxmapio.c new file mode 100644 index 000000000..b9d54e3ca --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/jxmapio.c @@ -0,0 +1,120 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/jxmapio.c,v 1.2 1995/11/02 11:04:33 flo Exp $") + +/*++ + +Copyright (c) 1993 - 1994 Siemens Nixdorf Informationssysteme AG +Copyright (c) 1991 - 1994 Microsoft Corporation + +Module Name: + + jxmapio.c + +Abstract: + + This module implements the mapping of HAL I/O space for a SNI + or R4x00 system. + For use of EISA I/O Space during phase 0 we go via KSEG1_BASE + +Environment: + + Kernel mode + + +--*/ + +#include "halp.h" + +// +// Put all code for HAL initialization in the INIT section. It will be +// deallocated by memory management when phase 1 initialization is +// completed. +// + +#if defined(ALLOC_PRAGMA) + +#pragma alloc_text(INIT, HalpMapIoSpace) + +#endif + +// +// Define global data used to locate the EISA control space and the realtime +// clock registers. +// + +PVOID HalpEisaControlBase =(PVOID) (EISA_CONTROL_PHYSICAL_BASE | KSEG1_BASE); + +// +// be careful : HalpOnboardControlBase value is used before the init in xxinithl.c +// + +PVOID HalpOnboardControlBase=(PVOID) (EISA_CONTROL_PHYSICAL_BASE | KSEG1_BASE); + +PVOID HalpEisaMemoryBase =(PVOID) (EISA_MEMORY_PHYSICAL_BASE | KSEG1_BASE); + +BOOLEAN +HalpMapIoSpace ( + VOID + ) + +/*++ + +Routine Description: + + This routine maps the HAL I/O space for a MIPS R4x00 SNI + system (Phase 1, so the mapping goes via MmMapIoSpace()). + +Arguments: + + None. + +Return Value: + + If the initialization is successfully completed, than a value of TRUE + is returned. Otherwise, a value of FALSE is returned. + +--*/ + +{ + PHYSICAL_ADDRESS physicalAddress; + + // + // Map EISA control space. Map all 16 slots. This is done so the NMI + // code can probe the cards. + // (64KB I/O Space) + // + + physicalAddress.HighPart = 0; + physicalAddress.LowPart = EISA_CONTROL_PHYSICAL_BASE; + HalpEisaControlBase = MmMapIoSpace(physicalAddress, + PAGE_SIZE * 16, + FALSE); + + HalpOnboardControlBase = HalpEisaControlBase; + + // + // Map EISA memory space so the x86 bios emulator emulator can + // initialze a video adapter in an EISA/Isa slot. + // (first 1MB only to have access to Card Bioses) + // We do not have to call HalTranslateBusAddress on our SNI machines, + // because we always use EISA_MEMORY_PHYSICAL_BASE for Extension Cards + // on all machines + // + + physicalAddress.HighPart = 0; + physicalAddress.LowPart = EISA_MEMORY_PHYSICAL_BASE; + HalpEisaMemoryBase = MmMapIoSpace(physicalAddress, + PAGE_SIZE * 256, + FALSE); + // + // If either mapped address is NULL, then return FALSE as the function + // value. Otherwise, return TRUE. + // + + if ((HalpEisaControlBase == NULL) || + (HalpOnboardControlBase == NULL) || + (HalpEisaMemoryBase == NULL)) { + return FALSE; + } else { + return TRUE; + } +} diff --git a/private/ntos/nthals/halsnip/mips/jxport.c b/private/ntos/nthals/halsnip/mips/jxport.c new file mode 100644 index 000000000..d56b8c559 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/jxport.c @@ -0,0 +1,805 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/jxport.c,v 1.1 1995/07/20 15:58:02 flo Exp $") + +/*++ + +Copyright (c) 1991-1994 Microsoft Corporation + +Module Name: + + jxport.c + +Abstract: + + This module implements the code that provides communication between + the kernel debugger on a MIPS R4000 system and the host + system. + +Environment: + + Kernel mode + +Revision History: + +--*/ + +#include "halp.h" +#include "jazzserp.h" + +// set the correct divisor for the SNI serial ports / quartz clock +#if defined(SNI) + #undef BAUD_RATE_9600 + #undef BAUD_RATE_19200 + #define BAUD_RATE_9600 12 + #define BAUD_RATE_19200 6 +#endif // SNI + + +#define HEADER_FILE +#include "kxmips.h" + + +VOID +HalpGetDivisorFromBaud( + IN ULONG ClockRate, + IN LONG DesiredBaud, + OUT PSHORT AppropriateDivisor + ); + + +#pragma alloc_text(INIT,HalpGetDivisorFromBaud) + + +// +// BUGBUG Temporarily, we use counter to do the timeout +// + +#define TIMEOUT_COUNT 1024*512 + +// +// BUGBUG Temp until we have a configuration manager. +// + +PUCHAR KdComPortInUse = NULL; +BOOLEAN KdUseModemControl = FALSE; + +// +// Define serial port read and write addresses. +// + +#if defined(USE_COM2) + +// Assume COM2 for the kernel debugger. + +#define SP_READ ((PSP_READ_REGISTERS) ((ULONG)HalpOnboardControlBase + SERIAL1_RELATIVE_BASE)) +#define SP_WRITE ((PSP_WRITE_REGISTERS)((ULONG)HalpOnboardControlBase + SERIAL1_RELATIVE_BASE)) + + +#else + +// Assume COM1 for the kernel debugger. + +#define SP_READ ((PSP_READ_REGISTERS) ((ULONG)HalpOnboardControlBase + SERIAL0_RELATIVE_BASE)) +#define SP_WRITE ((PSP_WRITE_REGISTERS)((ULONG)HalpOnboardControlBase + SERIAL0_RELATIVE_BASE)) + +#endif +// +// Define forward referenced prototypes. +// + +SP_LINE_STATUS +KdReadLsr ( + IN BOOLEAN WaitReason + ); + +// +// Define baud rate divisor to be used on the debugger port. +// + +SHORT HalpBaudRateDivisor = BAUD_RATE_19200; + + +ULONG +HalpGetByte ( + IN PCHAR Input, + IN BOOLEAN Wait + ) + +/*++ + +Routine Description: + + This routine gets a byte from the serial port used by the kernel + debugger. + +Arguments: + + Input - Supplies a pointer to a variable that receives the input + data byte. + + Wait - Supplies a boolean value that detemines whether a timeout + is applied to the input operation. + +Return Value: + + CP_GET_SUCCESS is returned if a byte is successfully read from the + kernel debugger line. + + CP_GET_ERROR is returned if an error is encountered during reading. + + CP_GET_NODATA is returned if timeout occurs. + +--*/ + +{ + + SP_LINE_STATUS LsrByte; + UCHAR DataByte; + ULONG TimeoutCount; + + // + // Attempt to read a byte from the debugger port until a byte is + // available or until a timeout occurs. + // + + TimeoutCount = Wait ? TIMEOUT_COUNT : 1; + do { + TimeoutCount -= 1; + + // + // Wait until data is available in the receive buffer. + // + + KeStallExecutionProcessor(1); + LsrByte = KdReadLsr(TRUE); + if (LsrByte.DataReady == 0) { + continue; + } + + // + // Read input byte and store in callers buffer. + // + + *Input = READ_REGISTER_UCHAR(&SP_READ->ReceiveBuffer); + + // + // If using modem controls, then skip any incoming data while + // ReceiveData not set. + // + + if (KdUseModemControl) { + DataByte = READ_REGISTER_UCHAR(&SP_READ->ModemStatus); + if ( ((PSP_MODEM_STATUS)&DataByte)->ReceiveDetect == 0) { + continue; + } + } + + // + // Return function value as the not of the error indicators. + // + + if (LsrByte.ParityError || + LsrByte.FramingError || + LsrByte.OverrunError || + LsrByte.BreakIndicator) { + return CP_GET_ERROR; + } + + return CP_GET_SUCCESS; + } while(TimeoutCount != 0); + + return CP_GET_NODATA; +} + +BOOLEAN +KdPortInitialize ( + PDEBUG_PARAMETERS DebugParameters, + PLOADER_PARAMETER_BLOCK LoaderBlock, + BOOLEAN Initialize + ) + +/*++ + +Routine Description: + + This routine initializes the serial port used by the kernel debugger + and must be called during system initialization. + +Arguments: + + DebugParameter - Supplies a pointer to the debug port parameters. + + LoaderBlock - Supplies a pointer to the loader parameter block. + + Initialize - Specifies a boolean value that determines whether the + debug port is initialized or just the debug port parameters + are captured. + +Return Value: + + A value of TRUE is returned is the port was successfully initialized. + Otherwise, a value of FALSE is returned. + +--*/ + +{ + + PCONFIGURATION_COMPONENT_DATA ConfigurationEntry; + UCHAR DataByte; + PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor; + PCM_SERIAL_DEVICE_DATA DeviceData; + PCM_PARTIAL_RESOURCE_LIST List; + ULONG MatchKey; + ULONG BaudRate; + ULONG BaudClock; + + + // + // Find the configuration information for the first serial port. + // + + if (LoaderBlock != NULL) { + MatchKey = 0; + ConfigurationEntry = KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot, + ControllerClass, + SerialController, + &MatchKey); + + } else { + ConfigurationEntry = NULL; + } + + if (DebugParameters->BaudRate != 0) { + BaudRate = DebugParameters->BaudRate; + } else { + BaudRate = 19200; + } + + // + // If the serial configuration entry was not found or the frequency + // specified is not supported, then default the baud clock to 800000. + // + + BaudClock = 8000000; + if (ConfigurationEntry != NULL) { + List = (PCM_PARTIAL_RESOURCE_LIST)ConfigurationEntry->ConfigurationData; + Descriptor = &List->PartialDescriptors[List->Count]; + DeviceData = (PCM_SERIAL_DEVICE_DATA)Descriptor; + if ((DeviceData->BaudClock == 1843200) || + (DeviceData->BaudClock == 4233600) || + (DeviceData->BaudClock == 8000000)) { + BaudClock = DeviceData->BaudClock; + } + } + + HalpGetDivisorFromBaud( + BaudClock, + BaudRate, + &HalpBaudRateDivisor + ); + + // + // If the debugger is not being enabled, then return. + // + + if (Initialize == FALSE) { + return TRUE; + } + +// +// BUGBUG the FW configuration sets the serial 0 Port config relativ to +// the EISA/ISA Base Address, so the serial driver doesn't get the right +// information when debugging is enabled .... +// + +#if defined(USE_COM2) + KdComPortInUse=(PUCHAR)(SERIAL1_PHYSICAL_BASE); +#else + KdComPortInUse=(PUCHAR)(SERIAL0_PHYSICAL_BASE); +#endif + + + // + // Clear the divisor latch, clear all interrupt enables, and reset and + // disable the FIFO's. + // + + WRITE_REGISTER_UCHAR(&SP_WRITE->LineControl, 0x0); + WRITE_REGISTER_UCHAR(&SP_WRITE->InterruptEnable, 0x0); + DataByte = 0; + ((PSP_FIFO_CONTROL)(&DataByte))->ReceiveFifoReset = 1; + ((PSP_FIFO_CONTROL)(&DataByte))->TransmitFifoReset = 1; + WRITE_REGISTER_UCHAR(&SP_WRITE->FifoControl, DataByte); + + // + // Set the divisor latch and set the baud rate. + // + ((PSP_LINE_CONTROL)(&DataByte))->DivisorLatch = 1; + WRITE_REGISTER_UCHAR(&SP_WRITE->LineControl, DataByte); + WRITE_REGISTER_UCHAR(&SP_WRITE->TransmitBuffer,(UCHAR)(HalpBaudRateDivisor&0xFF)); + + WRITE_REGISTER_UCHAR(&SP_WRITE->InterruptEnable,(UCHAR)(HalpBaudRateDivisor>>8)); + + // + // Clear the divisor latch and set the character size to eight bits + // with one stop bit and no parity checking. + // + + DataByte = 0; + ((PSP_LINE_CONTROL)(&DataByte))->CharacterSize = EIGHT_BITS; + WRITE_REGISTER_UCHAR(&SP_WRITE->LineControl, DataByte); + + // + // Set data terminal ready and request to send. + // + + DataByte = 0; + ((PSP_MODEM_CONTROL)(&DataByte))->DataTerminalReady = 1; + ((PSP_MODEM_CONTROL)(&DataByte))->RequestToSend = 1; + WRITE_REGISTER_UCHAR(&SP_WRITE->ModemControl, DataByte); + + return TRUE; +} + +ULONG +KdPortGetByte ( + OUT PUCHAR Input + ) + +/*++ + +Routine Description: + + This routine gets a byte from the serial port used by the kernel + debugger. + + N.B. It is assumed that the IRQL has been raised to the highest + level, and necessary multiprocessor synchronization has been + performed before this routine is called. + +Arguments: + + Input - Supplies a pointer to a variable that receives the input + data byte. + +Return Value: + + CP_GET_SUCCESS is returned if a byte is successfully read from the + kernel debugger line. + + CP_GET_ERROR is returned if an error is encountered during reading. + + CP_GET_NODATA is returned if timeout occurs. + +--*/ + +{ + + return HalpGetByte(Input, TRUE); +} + +ULONG +KdPortPollByte ( + OUT PUCHAR Input + ) + +/*++ + +Routine Description: + + This routine gets a byte from the serial port used by the kernel + debugger iff a byte is available. + + N.B. It is assumed that the IRQL has been raised to the highest + level, and necessary multiprocessor synchronization has been + performed before this routine is called. + +Arguments: + + Input - Supplies a pointer to a variable that receives the input + data byte. + +Return Value: + + CP_GET_SUCCESS is returned if a byte is successfully read from the + kernel debugger line. + + CP_GET_ERROR is returned if an error encountered during reading. + + CP_GET_NODATA is returned if timeout occurs. + +--*/ + +{ + + ULONG Status; + + // + // Save port status, map the serial controller, get byte from the + // debugger port is one is avaliable, restore port status, unmap + // the serial controller, and return the operation status. + // + + KdPortSave(); + Status = HalpGetByte(Input, FALSE); + KdPortRestore(); + return Status; +} + +VOID +KdPortPutByte ( + IN UCHAR Output + ) + +/*++ + +Routine Description: + + This routine puts a byte to the serial port used by the kernel debugger. + + N.B. It is assumed that the IRQL has been raised to the highest level, + and necessary multiprocessor synchronization has been performed + before this routine is called. + +Arguments: + + Output - Supplies the output data byte. + +Return Value: + + None. + +--*/ + +{ + + UCHAR DataByte; + + if (KdUseModemControl) { + // + // Modem control, make sure DSR, CTS and CD are all set before + // sending any data. + // + + for (; ;) { + DataByte = READ_REGISTER_UCHAR(&SP_READ->ModemStatus); + if ( ((PSP_MODEM_STATUS)&DataByte)->ClearToSend && + ((PSP_MODEM_STATUS)&DataByte)->DataSetReady && + ((PSP_MODEM_STATUS)&DataByte)->ReceiveDetect ) { + break; + } + + KdReadLsr(FALSE); + } + } + + // + // Wait for transmit ready. + // + + while (KdReadLsr(FALSE).TransmitHoldingEmpty == 0 ); + + // + // Wait for data set ready. + // + +// do { +// LsrByte = READ_REGISTER_UCHAR(&SP_READ->ModemStatus); +// } while (((PSP_MODEM_STATUS)(&LsrByte))->DataSetReady == 0); + + // + // Transmit data. + // + + WRITE_REGISTER_UCHAR(&SP_WRITE->TransmitBuffer, Output); + return; +} + +VOID +KdPortRestore ( + VOID + ) + +/*++ + +Routine Description: + + This routine restores the state of the serial port after the kernel + debugger has been active. + + N.B. This routine performs no function on the Jazz system. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + + return; +} + +VOID +KdPortSave ( + VOID + ) + +/*++ + +Routine Description: + + This routine saves the state of the serial port and initializes the port + for use by the kernel debugger. + + N.B. This routine performs no function on the Jazz system. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + return; +} + +SP_LINE_STATUS +KdReadLsr ( + IN BOOLEAN WaitReason + ) + +/*++ + +Routine Description: + + Returns current line status. + + If status which is being waited for is ready, then the function + checks the current modem status and causes a possible display update + of the current statuses. + +Arguments: + + WaitReason - Suuplies a boolean value that determines whether the line + status is required for a receive or transmit. + +Return Value: + + The current line status is returned as the function value. + +--*/ + +{ + + static UCHAR RingFlag = 0; + UCHAR DataLsr, DataMsr; + + // + // Get the line status for a recevie or a transmit. + // + + DataLsr = READ_REGISTER_UCHAR(&SP_READ->LineStatus); + if (WaitReason) { + + // + // Get line status for receive data. + // + + if (((PSP_LINE_STATUS)&DataLsr)->DataReady) { + return *((PSP_LINE_STATUS)&DataLsr); + } + + } else { + + // + // Get line status for transmit empty. + // + + if (((PSP_LINE_STATUS)&DataLsr)->TransmitEmpty) { + return *((PSP_LINE_STATUS)&DataLsr); + } + } + + DataMsr = READ_REGISTER_UCHAR(&SP_READ->ModemStatus); + RingFlag |= ((PSP_MODEM_STATUS)&DataMsr)->RingIndicator ? 1 : 2; + if (RingFlag == 3) { + + // + // The ring indicate line has toggled, use modem control from + // now on. + // + + KdUseModemControl = TRUE; + } + + return *((PSP_LINE_STATUS) &DataLsr); +} + +VOID +HalpGetDivisorFromBaud( + IN ULONG ClockRate, + IN LONG DesiredBaud, + OUT PSHORT AppropriateDivisor + ) + +/*++ + +Routine Description: + + This routine will determine a divisor based on an unvalidated + baud rate. + +Arguments: + + ClockRate - The clock input to the controller. + + DesiredBaud - The baud rate for whose divisor we seek. + + AppropriateDivisor - Given that the DesiredBaud is valid, the + SHORT pointed to by this parameter will be set to the appropriate + value. If the requested baud rate is unsupportable on the machine + return a divisor appropriate for 19200. + +Return Value: + + none. + +--*/ + +{ + + SHORT calculatedDivisor; + ULONG denominator; + ULONG remainder; + + // + // Allow up to a 1 percent error + // + + ULONG maxRemain18 = 18432; + ULONG maxRemain30 = 30720; + ULONG maxRemain42 = 42336; + ULONG maxRemain80 = 80000; + ULONG maxRemain; + + // + // Reject any non-positive bauds. + // + + denominator = DesiredBaud*(ULONG)16; + + if (DesiredBaud <= 0) { + + *AppropriateDivisor = -1; + + } else if ((LONG)denominator < DesiredBaud) { + + // + // If the desired baud was so huge that it cause the denominator + // calculation to wrap, don't support it. + // + + *AppropriateDivisor = -1; + + } else { + + if (ClockRate == 1843200) { + maxRemain = maxRemain18; + } else if (ClockRate == 3072000) { + maxRemain = maxRemain30; + } else if (ClockRate == 4233600) { + maxRemain = maxRemain42; + } else { + maxRemain = maxRemain80; + } + + calculatedDivisor = (SHORT)(ClockRate / denominator); + remainder = ClockRate % denominator; + + // + // Round up. + // + + if (((remainder*2) > ClockRate) && (DesiredBaud != 110)) { + + calculatedDivisor++; + } + + + // + // Only let the remainder calculations effect us if + // the baud rate is > 9600. + // + + if (DesiredBaud >= 9600) { + + // + // If the remainder is less than the maximum remainder (wrt + // the ClockRate) or the remainder + the maximum remainder is + // greater than or equal to the ClockRate then assume that the + // baud is ok. + // + + if ((remainder >= maxRemain) && ((remainder+maxRemain) < ClockRate)) { + calculatedDivisor = -1; + } + + } + + // + // Don't support a baud that causes the denominator to + // be larger than the clock. + // + + if (denominator > ClockRate) { + + calculatedDivisor = -1; + + } + + // + // Ok, Now do some special casing so that things can actually continue + // working on all platforms. + // + + if (ClockRate == 1843200) { + + if (DesiredBaud == 56000) { + calculatedDivisor = 2; + } + + } else if (ClockRate == 3072000) { + + if (DesiredBaud == 14400) { + calculatedDivisor = 13; + } + + } else if (ClockRate == 4233600) { + + if (DesiredBaud == 9600) { + calculatedDivisor = 28; + } else if (DesiredBaud == 14400) { + calculatedDivisor = 18; + } else if (DesiredBaud == 19200) { + calculatedDivisor = 14; + } else if (DesiredBaud == 38400) { + calculatedDivisor = 7; + } else if (DesiredBaud == 56000) { + calculatedDivisor = 5; + } + + } else if (ClockRate == 8000000) { + + if (DesiredBaud == 14400) { + calculatedDivisor = 35; + } else if (DesiredBaud == 56000) { + calculatedDivisor = 9; + } + + } + + *AppropriateDivisor = calculatedDivisor; + + } + + + if (*AppropriateDivisor == -1) { + + HalpGetDivisorFromBaud( + ClockRate, + 19200, + AppropriateDivisor + ); + + } + + +} diff --git a/private/ntos/nthals/halsnip/mips/jxreturn.c b/private/ntos/nthals/halsnip/mips/jxreturn.c new file mode 100644 index 000000000..f5f7c4711 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/jxreturn.c @@ -0,0 +1,286 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/jxreturn.c,v 1.6 1996/03/12 16:28:26 pierre Exp $") + +/*++ + + +Copyright (c) 1993-94 Siemens Nixdorf Informationssysteme AG +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + jxreturn.c + +Abstract: + + This module implements the HAL return to firmware function. + + +--*/ + +#include "halp.h" +#include "eisa.h" +#include "SNIregs.h" +#include "mpagent.h" + +VOID +HalpBootCpuRestart( + VOID + ); +VOID +HalpClearVGADisplay( + VOID + ); + +VOID +HalReturnToFirmware( + IN FIRMWARE_REENTRY Routine + ) + + + +/*++ + +Routine Description: + + This function returns control to the specified firmware routine. + In most cases it generates a soft reset. + +Arguments: + + Routine - Supplies a value indicating which firmware routine to invoke. + +Return Value: + + Does not return. + +--*/ + +{ + KIRQL OldIrql; + UCHAR DataByte; + + // + // Disable Interrupts. + // + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + // + // Case on the type of return. + // + + switch (Routine) { + case HalHaltRoutine: + + // + // Hang looping. + // + + // power off asked by DCU/IDC (power - fan or ... failure) + if (((ULONG)(((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EipRoutine) != (ULONG)-1) && + (((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EipHalInfo == 1)) + + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EipRoutine( + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EipContext + ); + for (;;) {} + + case HalPowerDownRoutine: + + // power off always done by DCU + + if ((ULONG)(((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EipRoutine) != (ULONG)-1) + + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EipRoutine( + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EipContext + ); + // + // PowerOff is done by the SNI machines by writing the Power_Off bit to the machine control register ... + // + if (HalpIsTowerPci){ + WRITE_REGISTER_ULONG((PULONG) PCI_TOWER_DCU_CONTROL, DC_POWEROFF); + }else{ + WRITE_REGISTER_UCHAR((PUCHAR) PCI_MCR_ADDR, PCI_MCR_POWEROFF); + } + + for (;;) {} // hang looping + + + case HalRestartRoutine: + case HalRebootRoutine: + case HalInteractiveModeRoutine: + + // power off asked by DCU/IDC (power - fan or ... failure) + if (((ULONG)(((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EipRoutine) != (ULONG)-1) && + (((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EipHalInfo == 1)) + + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EipRoutine( + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EipContext + ); + + if (HalpIsMulti) { + ULONG Mask,i; + + for (i=0;i<HalpIsMulti;i++) + if (((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->ActiveProcessor[PCR->Number]) + Mask |= 1<<i; + + + Mask = Mask & ~(PCR->SetMember); +#if DBGG + DbgPrint("Send message RESTART to maskcpu = %x \n",Mask); +#endif + + HalpRequestIpi(Mask,MPA_RESTART_MESSAGE); + // + // if this is not the Boot CPU, we call a special Firmware entry to stop it + // + + // + // remove this processor from the list of active processors + // + + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->ActiveProcessor[PCR->Number]=0; + + if (PCR->Number ) { + +#if DBGG + DbgPrint(" Reinit slave %x \n", ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->reinit_slave); +#endif + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->reinit_slave(); + + } else HalpBootCpuRestart(); + } + + HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode + HalDisplayString("\n"); + HalpClearVGADisplay(); + HalDisplayString("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); + HalDisplayString(" ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»\n"); + HalDisplayString(" º º\n"); + HalDisplayString(" º Restart in Progress º\n"); + HalDisplayString(" º º\n"); + HalDisplayString(" ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ\n"); + + DataByte = READ_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpOnboardControlBase)->ExtendedNmiResetControl); + + ((PNMI_EXTENDED_CONTROL) &DataByte)->BusReset = 1; + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpOnboardControlBase)->ExtendedNmiResetControl, + DataByte + ); + + KeStallExecutionProcessor(10000); + + ((PNMI_EXTENDED_CONTROL) &DataByte)->BusReset = 0; + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpOnboardControlBase)->ExtendedNmiResetControl, + DataByte + ); + + ArcReboot(); + + for (;;) ; + + default: + DbgPrint("HalReturnToFirmware invalid argument\n"); + KeLowerIrql(OldIrql); + DbgBreakPoint(); + } +} + +VOID +HalpBootCpuRestart( + VOID + ) + +/*++ + +Routine Description: + + This function returns control to the firmware Arcreboot routine. + it waits until all other cpu's have beet shut down. + this code is executed only on the boot cpu + +Arguments: + + None + +Return Value: + + Does not return. + +--*/ +{ + UCHAR DataByte; + ULONG cpt; + + + HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode + HalDisplayString("\n"); + HalpClearVGADisplay(); + HalDisplayString("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); + HalDisplayString(" ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»\n"); + HalDisplayString(" º º\n"); + HalDisplayString(" º Restart in Progress º\n"); + HalDisplayString(" º º\n"); + HalDisplayString(" ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ\n"); + + cpt = 0; + while(*(PULONG)(& (((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->ActiveProcessor[0]) )) { + KeStallExecutionProcessor(500000); + ++cpt;if (cpt == 20) break; + } + // + // if there are still ssome processors active, we do a reset of the entire machine + // + if (*(PULONG)(& (((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->ActiveProcessor[0]) )) { + +#if DBG + DbgPrint(" Some processors did not answer . Reset machine started. \n"); +#endif + if (HalpIsTowerPci) { + WRITE_REGISTER_ULONG((PULONG) PCI_TOWER_DCU_CONTROL, DC_SWRESET); + }else { + + WRITE_REGISTER_UCHAR((PUCHAR) PCI_MCR_ADDR, PCI_MCR_SOFTRESET); + } + } else { + +#if DBG + DbgPrint("Reboot started \n"); +#endif + + } + + DataByte = READ_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpOnboardControlBase)->ExtendedNmiResetControl); + + ((PNMI_EXTENDED_CONTROL) &DataByte)->BusReset = 1; + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpOnboardControlBase)->ExtendedNmiResetControl, + DataByte + ); + + KeStallExecutionProcessor(10000); + + ((PNMI_EXTENDED_CONTROL) &DataByte)->BusReset = 0; + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpOnboardControlBase)->ExtendedNmiResetControl, + DataByte + ); + + + ArcReboot(); + + for (;;) ; +} + + + + + diff --git a/private/ntos/nthals/halsnip/mips/jxsysint.c b/private/ntos/nthals/halsnip/mips/jxsysint.c new file mode 100644 index 000000000..1e32051c2 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/jxsysint.c @@ -0,0 +1,335 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/jxsysint.c,v 1.3 1996/03/04 13:19:54 pierre Exp $") +/*++ + +Copyright (c) 1993-94 Siemens Nixdorf Informationssysteme AG +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + jxsysint.c + +Abstract: + + This module implements the HAL enable/disable system interrupt, and + request interprocessor interrupt routines for a MIPS R3000 or R4000 + SNI system. + +Environment: + + Kernel mode + +--*/ + +#include "halp.h" + + +VOID +HalDisableSystemInterrupt ( + IN ULONG Vector, + IN KIRQL Irql + ) + +/*++ + +Routine Description: + + This routine disables the specified system interrupt. + +Arguments: + + Vector - Supplies the vector of the system interrupt that is disabled. + + Irql - Supplies the IRQL of the interrupting source. + +Return Value: + + None. + +--*/ + +{ + + KIRQL OldIrql; + + + // + // Raise IRQL to the highest level. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + KiAcquireSpinLock(&HalpSystemInterruptLock); + + + // + // If the vector number is within the range of the onboard interrupts, then + // disable the onboard interrrupt. + // This may be an Isa (Desktop) or Isa/Eisa (Minitower) Interrupt + // + + if (Vector >= ONBOARD_VECTORS && + Vector <= MAXIMUM_ONBOARD_VECTOR && + Irql == EISA_DEVICE_LEVEL) { + HalpDisableOnboardInterrupt(Vector); + } + + + // + // If the vector number is within the range of the EISA interrupts, then + // disable the EISA interrrupt on the Eisa Backplane (Eisa Extension). + // + + else if (Vector >= EISA_VECTORS && + Vector <= MAXIMUM_EISA_VECTOR && + Irql == EISA_DEVICE_LEVEL) { + + HalpDisableEisaInterrupt(Vector); + } + + // + // Lower IRQL to the previous level. + // + + KiReleaseSpinLock(&HalpSystemInterruptLock); + KeLowerIrql(OldIrql); + + return; +} + +BOOLEAN +HalEnableSystemInterrupt ( + IN ULONG Vector, + IN KIRQL Irql, + IN KINTERRUPT_MODE InterruptMode + ) + +/*++ + +Routine Description: + + This routine enables the specified system interrupt. + +Arguments: + + Vector - Supplies the vector of the system interrupt that is enabled. + + Irql - Supplies the IRQL of the interrupting source. + + InterruptMode - Supplies the mode of the interrupt; LevelSensitive or + Latched. + +Return Value: + + TRUE if the system interrupt was enabled + +--*/ + +{ + + KIRQL OldIrql; + + // + // Raise IRQL to the highest level. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + KiAcquireSpinLock(&HalpSystemInterruptLock); + + // + // If the vector number is within the range of the onboard interrupts, then + // enable the onboard interrrupt and set the Level/Edge register to latched, + // because the onboard Opti 499 (Desktop)is a real Isa Controler and cannot share interrupts. + // even the i82350 Chipset on the Minitower cannot share interrupts (why ?) + // + + if (Vector >= ONBOARD_VECTORS && + Vector <= MAXIMUM_ONBOARD_VECTOR && + Irql == EISA_DEVICE_LEVEL) { + + HalpEnableOnboardInterrupt( Vector, InterruptMode); + } + + // + // If the vector number is within the range of the EISA interrupts, then + // enable the EISA interrrupt in the Eisa Backplane (Eisa Extension) and set the Level/Edge register. + // + + else if (Vector >= EISA_VECTORS && + Vector <= MAXIMUM_EISA_VECTOR && + Irql == EISA_DEVICE_LEVEL) { + HalpEnableEisaInterrupt( Vector, InterruptMode); + } + + // + // Lower IRQL to the previous level. + // + + KiReleaseSpinLock(&HalpSystemInterruptLock); + KeLowerIrql(OldIrql); + + + return TRUE; +} + +ULONG +HalGetInterruptVector( + IN INTERFACE_TYPE InterfaceType, + IN ULONG BusNumber, + 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: + + InterfaceType - Supplies the type of bus which the vector is for. + + BusNumber - Supplies the bus number for the device. + + BusInterruptLevel - Supplies the bus specific interrupt level. + + BusInterruptVector - Supplies the bus specific interrupt vector. + + Irql - Returns the system request priority. + + Affinity - Returns the affinity for the requested vector + +Return Value: + + Returns the system interrupt vector corresponding to the specified device. + +--*/ + +{ + + + *Affinity = 1; + + // + // If this is for the internal bus then just return the passed parameter. + // + + if (InterfaceType == Internal) { + + if (BusInterruptVector >= ONBOARD_VECTORS && + BusInterruptVector <= MAXIMUM_ONBOARD_VECTOR ) { + + // + // this is one of the onboard components of the PC core + // (floppy, serial, parallel, mouse etc.) + // they should be configured in the Firmware tree with an Offset of + // ONBOARD_VECTORS (e.g. 0x10 to make them different to the real onboard components + // like scsi or ethernet) and with an Irql of EISA_DEVICE_LEVEL (actually 4) + // we need Firmware release 1.04 or later ... + // + + // + // Bus interrupt vector 2 of Onboard PC core interrupts is actually mapped to + // vector 9 in the Isa/Eisa hardware. + // + + if (BusInterruptVector == ONBOARD_VECTORS + 2) { + BusInterruptVector = ONBOARD_VECTORS + 9; + } + + // + // The IRQL level is always equal to the EISA level. + // + + *Irql = EISA_DEVICE_LEVEL; + + return(BusInterruptVector); + } + + // + // this is another special case of the DCU Interrupt for PCI Tower + // we have an agreement with the DCU developer + // we meet each other on InterruptVector 15, so we limit the Irql to Device Level + // + + if ( BusInterruptVector == DCU_VECTOR ) { + + if (HalpIsTowerPci) { + *Irql = (KIRQL) INT6_LEVEL; + // if more than one proc , DCU Interrupt is connected to proc 1 + if (HalpIsMulti !=0) *Affinity = 2; + return(BusInterruptVector); + } else { + *Irql = EISA_DEVICE_LEVEL; + return(BusInterruptVector); + } + + } + + + // + // these are the "real" Onboard components (scsi and Ethernet) + // Return the passed parameters. + // + + *Irql = (KIRQL) BusInterruptLevel; + + return(BusInterruptVector); + } + + if (InterfaceType == PCIBus) { + + // + // Not on this system return nothing. + // + + *Irql = (KIRQL) SCSIEISA_LEVEL; + + + return(BusInterruptVector); + } + + if (InterfaceType != Isa && InterfaceType != Eisa) { + + // + // Not on this system return nothing. + // + + *Affinity = 0; + *Irql = 0; + return(0); + } + + // + // Isa/Eisa Interrupts which are not configured in the Firmware + // (boards should be located in the Expansion Slots ...) + // The IRQL level is always equal to the EISA level. + // WARNING: some driver call HalGetInterruptVector + // with the BusInterruptLevel == BusInterruptVector + // but some call it with different values. + // In this part of the source tree we match the Jazz reference + // sources (see Internal handling; which is different) + // + + *Irql = EISA_DEVICE_LEVEL; + + // + // Bus interrupt 2 is actually mapped to bus interrupt 9 in the Isa/Eisa + // hardware. + // + + if (BusInterruptLevel == 2) { + BusInterruptLevel = 9; + } + + // + // all Isa/Eisa Interrupts should be handled by the onboard PC core + // + + return(BusInterruptLevel + ONBOARD_VECTORS); + +} diff --git a/private/ntos/nthals/halsnip/mips/jxtime.c b/private/ntos/nthals/halsnip/mips/jxtime.c new file mode 100644 index 000000000..a13ed8ec1 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/jxtime.c @@ -0,0 +1,359 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/jxtime.c,v 1.2 1995/11/02 11:04:33 flo Exp $") + +/*++ + +Copyright (c) 1993 SNI + +Module Name: + + SNItime.c + +Abstract: + + This module implements the HAL set/query realtime clock routines for + a MIPS R4000 SNI system. + +Environment: + + Kernel mode + +--*/ + +#include "halp.h" + + +#define NVINDEX_STATE 0x6 +#define NVSTATE_TODVALID 0x1 + + + +#define bcd_to_dec(x) ( ((((x) >> 4 ) & 0xf ) * 10 ) + ((x) & 0xf) ) +#define dec_to_bcd(x) ( (((x) / 10) << 4) | ((x) % 10) ) + + +#define RTC_NVRAM_SIZE 0x7ff // NVRAM size on this chip + +// definitions for rtc 146818 + +#define RTC_SECS 0 +#define RTC_SECA 1 +#define RTC_MINS 2 +#define RTC_MINA 3 +#define RTC_HOURS 4 +#define RTC_HOURA 5 +#define RTC_DAYW 6 +#define RTC_DAYM 7 +#define RTC_MONTH 8 +#define RTC_YEAR 9 +#define RTC_REGA 10 +#define RTC_REGB 11 +#define RTC_REGC 12 +#define RTC_REGD 13 +#define RTC_MEM1 14 +#define RTC_MEM2 128 + +/* + * Register B bit definitions + */ +#define RTCB_SET 0x80 /* inhibit date update */ +#define RTCB_PIE 0x40 /* enable periodic interrupt */ +#define RTCB_AIE 0x20 /* enable alarm interrupt */ +#define RTCB_UIE 0x10 /* enable update-ended interrupt */ +#define RTCB_SQWE 0x08 /* square wave enable */ +#define RTCB_DMBINARY 0x04 /* binary data (0 => bcd data) */ +#define RTCB_24HR 0x02 /* 24 hour mode (0 => 12 hour) */ +#define RTCB_DSE 0x01 /* daylight savings mode enable */ + +/* Time of Day Clock */ + +struct todc { + short htenths; + short hsecs; + short hmins; + short hhours; + short hdays; + short hweekday; + short hmonth; + short hyear; +}; + +/* masks to get valid information */ + +#define MASK_CENT_SECS 0xFF +#define MASK_SECS 0x7F +#define MASK_MINS 0x7F +#define MASK_HOURS 0x3F +#define MASK_DAY_W 0x07 +#define MASK_DAY_M 0x3F +#define MASK_MONTH 0x1F +#define MASK_YEAR 0xFF + +// +// the reference year (we have only two digits for the year on the chip) +// + +#define YRREF 1900 + + + +// +// Define forward referenced procedure prototypes. +// + +BOOLEAN +HalQueryRealTimeClock ( + OUT PTIME_FIELDS TimeFields + ); + +BOOLEAN +HalSetRealTimeClock ( + IN PTIME_FIELDS TimeFields + ); + +VOID +HalpWrite146818(struct todc *todp, PUCHAR index, PUCHAR data); + +VOID +HalpRead146818(struct todc *todp, PUCHAR index, PUCHAR data); + +VOID +HalpPciReadTodc(struct todc *todp); + +VOID +HalpPciWriteTodc(struct todc *todp); + +UCHAR +HalpReadRegister146818(PUCHAR index, PUCHAR data, int reg); + +VOID HalpWriteRegister146818(PUCHAR index, PUCHAR data, int reg, UCHAR val); + + + +/* Calendar clock : For PCI Minitower and Desktop systems, the RTC is part of + * --------------- the SUPER_IO pc87323. + * It is software compatible with rtc146818. + */ + +BOOLEAN +HalQueryRealTimeClock ( + OUT PTIME_FIELDS TimeFields + ) + +/*++ + +Routine Description: + + This routine queries the realtime clock. + + N.B. this comment stand in jxtime.c: + This routine is required to provide any synchronization necessary + to query the realtime clock information. + +Arguments: + + TimeFields - Supplies a pointer to a time structure that receives + the realtime clock information. + +Return Value: + + If the power to the realtime clock has not failed, then the time + values are read from the realtime clock and a value of TRUE is + returned. Otherwise, a value of FALSE is returned. + +--*/ + +{ + + register CSHORT month, dayweek, daymonth, year, hours, mins, secs, msecs; + struct todc ltodc; + KIRQL oldIrql; + + + KeRaiseIrql(HIGH_LEVEL, &oldIrql); + + HalpPciReadTodc(<odc); + + KeLowerIrql(oldIrql); + + msecs = 0; + secs = ltodc.hsecs; + mins = ltodc.hmins; + hours = ltodc.hhours; + daymonth = ltodc.hdays; + dayweek = ltodc.hweekday; + month = ltodc.hmonth; + year = ltodc.hyear; + + + if (TimeFields) + { + TimeFields->Year = year+YRREF; + TimeFields->Month = month; + TimeFields->Day = daymonth; + TimeFields->Weekday = dayweek; + TimeFields->Hour = hours; + TimeFields->Minute = mins; + TimeFields->Second = secs; + TimeFields->Milliseconds = msecs; + } + + return TRUE; + +} + +BOOLEAN +HalSetRealTimeClock ( + IN PTIME_FIELDS TimeFields + ) + +/*++ + +Routine Description: + + This routine sets the realtime clock. + + N.B. this comment stand in jxtime.c: + This routine is required to provide anq synchronization necessary + to set the realtime clock information. + +Arguments: + + TimeFields - Supplies a pointer to a time structure that specifies the + realtime clock information. + +Return Value: + + If the power to the realtime clock has not failed, then the time + values are written to the realtime clock and a value of TRUE is + returned. Otherwise, a value of FALSE is returned. + +--*/ + +{ + + struct todc ltodc; + + KIRQL oldIrql; + UCHAR year, month, daymonth, dayweek, hours, mins, secs, msecs; + + // + // If the realtime clock battery is still functioning, then write + // the realtime clock values, and return a function value of TRUE. + // Otherwise, return a function value of FALSE. + // + + // this part has to be written + // if (...) return FALSE; + year = (UCHAR) ( (TimeFields->Year - YRREF) % 100 ); + month = (UCHAR) TimeFields->Month; + daymonth = (UCHAR) TimeFields->Day; + dayweek = (UCHAR) TimeFields->Weekday; + hours = (UCHAR) TimeFields->Hour; + mins = (UCHAR) TimeFields->Minute; + secs = (UCHAR) TimeFields->Second; + msecs = (UCHAR) TimeFields->Milliseconds; + + + ltodc.htenths = 0; + ltodc.hsecs = secs; + ltodc.hmins = mins; + ltodc.hhours = hours; + ltodc.hdays = daymonth; + ltodc.hweekday = dayweek; + ltodc.hmonth = month; + ltodc.hyear = year; + + KeRaiseIrql(HIGH_LEVEL, &oldIrql); + + HalpPciWriteTodc(<odc); + + KeLowerIrql(oldIrql); + + + + return TRUE; + +} +/* HAL_RTODC() */ +VOID +HalpPciReadTodc(struct todc *todp) +{ + PUCHAR rtc_index = (PUCHAR) RTC_ADDR_PCIMT; + PUCHAR rtc_data = (PUCHAR) RTC_DATA_PCIMT; + HalpRead146818(todp,rtc_index,rtc_data); +} + +/* HAL_WTODC() */ +VOID +HalpPciWriteTodc(struct todc *todp) +{ + + PUCHAR rtc_index = (PUCHAR) RTC_ADDR_PCIMT; + PUCHAR rtc_data = (PUCHAR)RTC_DATA_PCIMT; + HalpWrite146818(todp, rtc_index, rtc_data); +} + + +VOID +HalpWrite146818(struct todc *todp, PUCHAR index, PUCHAR data) +{ + UCHAR temp; + /* + * Write information to rtc146818 chip + */ + HalpWriteRegister146818(index,data,RTC_REGB,temp=(HalpReadRegister146818(index,data,RTC_REGB)|RTCB_SET)); + HalpWriteRegister146818(index,data,RTC_SECS,dec_to_bcd(todp->hsecs)&MASK_SECS); + HalpWriteRegister146818(index,data,RTC_MINS,dec_to_bcd(todp->hmins)&MASK_MINS); + HalpWriteRegister146818(index,data,RTC_HOURS,dec_to_bcd(todp->hhours)&MASK_HOURS); + HalpWriteRegister146818(index,data,RTC_DAYM,dec_to_bcd(todp->hdays)&MASK_DAY_M); + HalpWriteRegister146818(index,data,RTC_DAYW,dec_to_bcd(todp->hweekday)&MASK_DAY_W); + HalpWriteRegister146818(index,data,RTC_MONTH,dec_to_bcd(todp->hmonth)&MASK_MONTH); + + HalpWriteRegister146818(index,data,RTC_YEAR,dec_to_bcd(todp->hyear)&MASK_YEAR); + + + + HalpWriteRegister146818(index,data,RTC_REGB, temp &= ~RTCB_SET); +} + +VOID +HalpRead146818(struct todc *todp, PUCHAR index, PUCHAR data) +{ + UCHAR temp; + + HalpWriteRegister146818(index,data,RTC_REGB,temp=(HalpReadRegister146818(index,data,RTC_REGB)|RTCB_SET)); + + todp->htenths = 0; + todp->hsecs=bcd_to_dec(HalpReadRegister146818(index,data,RTC_SECS)&MASK_SECS); + todp->hmins=bcd_to_dec(HalpReadRegister146818(index,data,RTC_MINS)&MASK_MINS); + todp->hhours=bcd_to_dec(HalpReadRegister146818(index,data,RTC_HOURS)&MASK_HOURS); + todp->hdays=bcd_to_dec(HalpReadRegister146818(index,data,RTC_DAYM)&MASK_DAY_M); + todp->hweekday=bcd_to_dec(HalpReadRegister146818(index,data,RTC_DAYW)&MASK_DAY_W); + todp->hmonth=bcd_to_dec(HalpReadRegister146818(index,data,RTC_MONTH)&MASK_MONTH); + todp->hyear=bcd_to_dec(HalpReadRegister146818(index,data,RTC_YEAR)&MASK_YEAR); + + HalpWriteRegister146818(index,data,RTC_REGB, temp &= ~RTCB_SET); +} + + + +UCHAR +HalpReadRegister146818(PUCHAR index, PUCHAR data, int reg) +{ + WRITE_REGISTER_UCHAR(index,reg); + // *index = reg; + // wbflush(); + // return(*data) + return(READ_REGISTER_UCHAR(data)); +} + +VOID HalpWriteRegister146818(PUCHAR index, PUCHAR data, int reg, UCHAR val) +{ + WRITE_REGISTER_UCHAR(index,reg); +// *index = reg; +// wbflush(); + WRITE_REGISTER_UCHAR(data, val); +// *data = val; +// wbflush(); +} + diff --git a/private/ntos/nthals/halsnip/mips/jxusage.c b/private/ntos/nthals/halsnip/mips/jxusage.c new file mode 100644 index 000000000..b39cab418 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/jxusage.c @@ -0,0 +1,47 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/jxusage.c,v 1.1 1995/07/20 15:58:57 flo Exp $") + +/*++ + +Copyright (c) 1990-1994 Microsoft Corporation + +Module Name: + + jxusage.c + +Abstract: + + The module reports the io resources in use by the JAZZ hal. + + +--*/ + +#include "halp.h" + + +VOID +HalReportResourceUsage( + VOID + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + // + // BUGBUG: hal resouce usage reporting needs to be added here + // + + // IoReportHalResourceUsage ( + // HalName, + // RawResourceList, + // TranslatedResourceList, + // ListSize + // ); + + return; +} diff --git a/private/ntos/nthals/halsnip/mips/mpagent.c b/private/ntos/nthals/halsnip/mips/mpagent.c new file mode 100644 index 000000000..7420911ff --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/mpagent.c @@ -0,0 +1,745 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/mpagent.c,v 1.7 1996/02/23 17:55:12 pierre Exp $") + +/*++ + +Copyright (c) 1993-94 Siemens Nixdorf Informationssysteme AG +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + mpagent.c + +Abstract: + + This module implements the routines dealing with the SNI MP Agent on + SNI system. + +Environment: + + Kernel mode + +--*/ + +#include "halp.h" +#include "MPagent.h" + +extern VOID +KeUpdateRunTime( + IN struct _KTRAP_FRAME *TrapFrame + ); + + +VOID +HalpInitMPAgent( + IN ULONG Number + ) +/*++ + +Routine Description: + + This routine initializes the MutiProcessor_Agent chipset: + - reset an eventual MP_Agent fatal error, + - enable message passing (send/receive), + - fix routage for internal IT -> external IT, + - enable the internal interrupts, + - fix the mask for wanted external interrupts, + - disable Low Process Priority mode for + external interrupts, + - enable cache replace operator and update the + 'cache_rpl_buffer' global variable with a KSEG0 + 4 Mb reserved address. + +Arguments: + + Number : Logical number of the processor to be initialised + +Return Value: + + None. + +--*/ +{ + + + ULONG reg; + + + + // + // set up the snooper register + // + + reg = READ_REGISTER_ULONG(&(mpagent->snooper)); /* read the current value */ + reg |= (MPA_ENRCVMESS | /* enable message receiving */ + MPA_RSTSNPERR | /* reset an eventual old MP_Agent fatal error */ + MPA_ENLINK | /* enable read and link command */ + MPA_ENCOHREQ | /* enable coherency on the MP bus for this agent */ + 0); /* keep other fields */ + WRITE_REGISTER_ULONG(&(mpagent->snooper), reg); + + // RM300 with mono-processors boards with mp-agent can be configured with 1Mb cache, + // but the MP-agent tag RAM can be configured with 4Mb or 2MB. So we disable the MPbus error. + // (With monoprocessor machine the MP-agent tag ram is not useful at all ...) + + if ((HalpIsMulti) || (HalpIsTowerPci)) + reg &= ~(MPA_RSTSNPERR); /* enable new interrupt for MP_Agent fatal error */ + + WRITE_REGISTER_ULONG(&(mpagent->snooper), reg); + + + // + // cpu1reg register + // + + reg = READ_REGISTER_ULONG(&(mpagent->cpuda1reg)); /* read the current value */ + reg &= ~(MPA_ENDIRECT | /* disable LPP mechanism */ + MPA_ENTESTIT | /* disable interrupt test mode (interrupts from MPBus) */ + MPA_SELITI_MASK | /* reset old internal interrupt routage */ + 0); /* keep other fields */ + + reg |= MPA_SELITI_SR_IP7; /* send internal interrupts on external interrupt SR_IP7*/ + + WRITE_REGISTER_ULONG(&(mpagent->cpuda1reg), reg); + + // + // cpureg register + // + + reg = READ_REGISTER_ULONG(&(mpagent->cpureg)); /* read the current value */ + reg &= ~(MPA_ENINT_MASK | /* reset old values for interrupts */ + MPA_INTCONF_MASK| /* force falling edge for all interrupts */ + MPA_ENSHARED | /* don't put optimal mode for KERNEL */ + 0); + reg |= (MPA_ENSENDMSG | /* enable sending message */ + MPA_ENINT_MPBERR | /* enable internal interrupt for MP_Agent fatal error */ + MPA_ENINT_ITMSG1 | /* enable internal interrupt for message1 register */ + MPA_ENINT_ITMSG2 | /* enable internal interrupt for message2 register */ + MPA_ENINT_ITMSG3 | /* enable internal interrupt for message3 register */ + MPA_INTMSK | /* mask sent during external request stage */ + 0); /* keep other fields */ + + // + // external Interrupts routing in the MP Agent + // + + // pci tower -> force raising edges for all interrupts + + if (HalpIsTowerPci) reg |= MPA_INTCONF_MASK; + + // pci multi-processor machines => interrupts are centralized. + + if (Number == 0) reg |= MPA_ENINT_SR_IP3; // device interrupts are only processed by bootcpu. + // Timer processor 1 : IP5 for RM300 - IP6 for RM400 + + if (Number == 1) + if (!HalpIsTowerPci) reg |= MPA_ENINT_SR_IP5; + + WRITE_REGISTER_ULONG(&(mpagent->cpureg), reg); + + // + // clear pending interrupts by reading of the message registers + // + + reg = READ_REGISTER_ULONG(&(mpagent->datamsg1)); + reg = READ_REGISTER_ULONG(&(mpagent->datamsg2)); + reg = READ_REGISTER_ULONG(&(mpagent->datamsg3)); + + // Modif PS 20 June -> Don't use the operator with ASIC PCI -> BUGBUG + + if (HalpMpaCacheReplace == MPAGENT_RESERVED | KSEG0_BASE) { + reg = ((MPAGENT_RESERVED & // put the reserved physical address (4Mb long) + MPA_OP_ADDR_MASK) | + MPA_OP_ENABLE); // enable the operator + } else { + reg = 0; + } + + WRITE_REGISTER_ULONG(&(mpagent->mem_operator), reg); // for all procs (done for proc 0 in xxcache) + +} + + +VOID +HalpInitMAUIMPAgent( + ) +/*++ + +Routine Description: + + This routine initializes the MutiProcessor_Agent chipset: + - enable MAUI interrupt on the current processor + +Arguments: + + None + +Return Value: + + None. + +--*/ +{ + + + ULONG reg; + + // + // cpureg register + // + + reg = READ_REGISTER_ULONG(&(mpagent->cpureg)); /* read the current value */ + + reg |= MPA_ENINT_SR_IP6; + + WRITE_REGISTER_ULONG(&(mpagent->cpureg), reg); +} + + +VOID +HalRequestIpi( + IN ULONG CpuMask + ) +/*++ + +Routine Description: + + This routine requests an interprocessor interrupt on a set of processors. + That is done by using the message passing facility of the MPagent. + + N.B. This routine must ensure that the interrupt is posted at the target + processor(s) before returning. + +Arguments: + + Mask - Supplies the set of processors that are sent an interprocessor + interrupt. + +Return Value: + + None. + +--*/ +{ +ULONG physmask, cpt; +PRESTART_BLOCK NextRestartBlock; + + // CpuMask is a logical mask. We must use a mask with the physical + // numbers of cpus to communicate with the MP_Agent. + + physmask = 0;cpt = 0; + NextRestartBlock = SYSTEM_BLOCK->RestartBlock; + while (NextRestartBlock != NULL) { + + if (CpuMask & ( 1 << cpt)) { + physmask = (1 << (NextRestartBlock->ProcessorId)); + HalpSendIpi(physmask,MPA_KERNEL_MESSAGE); + } + ++cpt ; NextRestartBlock = NextRestartBlock->NextRestartBlock; + } + +} + + VOID +HalpRequestIpi( + IN ULONG CpuMask, + IN ULONG msg_data + ) +/*++ + +Routine Description: + + This routine requests an interprocessor interrupt on a set of processors. + That is done by using the message passing facility of the MPagent. + + N.B. This routine must ensure that the interrupt is posted at the target + processor(s) before returning. + +Arguments: + + Mask - Supplies the set of processors that are sent an interprocessor + interrupt. + +Return Value: + + None. + +--*/ +{ +ULONG physmask, cpt; +PRESTART_BLOCK NextRestartBlock; + + // CpuMask is a logical mask. We must use a mask with the physical + // numbers of cpus to communicate with the MP_Agent. + + physmask = 0;cpt = 0; + NextRestartBlock = SYSTEM_BLOCK->RestartBlock; + while (NextRestartBlock != NULL) { + + if (CpuMask & ( 1 << cpt)) { + physmask = (1 << (NextRestartBlock->ProcessorId)); + HalpSendIpi(physmask,msg_data); + } + ++cpt ; NextRestartBlock = NextRestartBlock->NextRestartBlock; + } + +} + + +VOID +HalpSendIpi( + IN ULONG pcpumask, + IN ULONG msg_data + ) +/*++ + +Routine Description: + + This routine sends an interprocessor interrupt on a set of processors. + That is done by using the message passing facility of the MPagent. + + N.B. This routine must ensure that the interrupt is posted at the target + processor(s) before returning. + +Arguments: + + pcpumask - Supplies the set of processors that are sent an interprocessor + interrupt. It contains physical numbers. + + msg_data _ Supplies the kind of message to be send : kernel demand or HAL internal demand. + +Return Value: + + None. + +--*/ +{ + +KIRQL OldIrql; +LONG msg_retries, watchdog; +ULONG msg_address, msg_status, itpend; + + + if (!pcpumask || !HalpIsMulti) { + + return; + + } + + // + // Raise IRQL to ??? level. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + + // + // form the Message Address register (Message register 1 / 2, CPUMask) + // The SNI MP Agent supports up to 4 CPU's + // + + if (msg_data ==MPA_TIMER_MESSAGE ) + msg_address = (pcpumask & MPA_CPUTARGET_MASK) | MPA_REGTARGET_MSG2; + else + msg_address = (pcpumask & MPA_CPUTARGET_MASK) | MPA_REGTARGET_MSG1; + + msg_data = ((msg_data << 24) | (pcpumask & MPA_CPUTARGET_MASK)); + + msg_retries = MPA_MSG_RETRY; + + /* + * Go on, just do it. + * If at first you don't succeed, then try, try and try again... + */ + + do { + + watchdog = 10; + + WRITE_REGISTER_ULONG(&(mpagent->msgaddress), msg_address); + WRITE_REGISTER_ULONG(&(mpagent->msgdata), msg_data); + + /* + * so, what happened? poll either until we know or the watchdog counter runs out + */ + do { + + KeStallExecutionProcessor(5); + + // + // read the message status register + // + msg_status = READ_REGISTER_ULONG(&(mpagent->msgstatus)); + + } while (((msg_status & MPA_VALSTAT) == 0) && watchdog--); + + +// KeLowerIrql(OldIrql); + + + if ((msg_status & MPA_VALSTAT) != MPA_VALSTAT) { + + + KeStallExecutionProcessor(100); +// KeRaiseIrql(HIGH_LEVEL, &OldIrql); + continue; + + } else { + + // + // okay, we have a Valid status bit + // so test of busy + + if ((msg_status & MPA_ERRMSG) == 0) { + + // + // all is fine + // + KeLowerIrql(OldIrql); + return; + + } else { + + // we have to verify that it is not a MPA_RETRY error. + + itpend = READ_REGISTER_ULONG(&(mpagent->itpend)); /* first read the interrupt pending MP_Agent register */ + + if (itpend & MPA_INTN_MPBERR) { + + ULONG snooper, cpureg, tmp ; + + cpureg = READ_REGISTER_ULONG(&(mpagent->cpureg)); /* read the current value */ + cpureg &= ~(MPA_ENINT_MPBERR /* disable interrupt for MP_Agent fatal error */ + ); /* keep other fields */ + WRITE_REGISTER_ULONG(&(mpagent->cpureg), cpureg); // write the new value in the MP_Agent register / + snooper = READ_REGISTER_ULONG(&(mpagent->snooper)); // read the current snooper register value/ + + tmp = READ_REGISTER_ULONG(&(mpagent->snpadreg)); /* read the current value */ + snooper |= MPA_RSTSNPERR; /* reset this MP_Agent fatal error */ + WRITE_REGISTER_ULONG(&(mpagent->snooper), snooper); /* write the new value in the MP_Agent register */ + + if ((snooper & MPA_MSEQERR == MPA_RETRYERR) || (snooper & MPA_MSEQERR ==0)) { + snooper &= ~(MPA_RSTSNPERR); /* stop reseting this MP_Agent fatal error */ + WRITE_REGISTER_ULONG(&(mpagent->snooper), snooper); /* write the new value in the MP_Agent register */ + cpureg = READ_REGISTER_ULONG(&(mpagent->cpureg)); /* read the current value */ + cpureg |= (MPA_ENINT_MPBERR); /* enable interrupt for MP_Agent fatal error */ + WRITE_REGISTER_ULONG(&(mpagent->cpureg), cpureg); // write the new value in the MP_Agent register / + + } + } + +// msg_retries = MPA_MSG_RETRY; + KeStallExecutionProcessor(100); +// KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + if (itpend & MPA_INTN_MPBERR) { + continue; + } else { + KeLowerIrql(OldIrql); + return; + } + } + + } + + +// KeRaiseIrql(HIGH_LEVEL, &OldIrql); + KeStallExecutionProcessor(10); + + } while (--msg_retries); /* message aborted, try again */ + + KeLowerIrql(OldIrql); + return; + +} + + +VOID +HalpProcessIpi( + IN struct _KTRAP_FRAME *TrapFrame + ) +/*++ + + Routine Description: + + This routine is entered as the result of an IP5 interrupt. This function + will looks at the MPagent to see if an IPI has just occurred. + + Arguments: + + None. + + Return Value: + + +--*/ +{ + ULONG itpend, msg_data; + + itpend = READ_REGISTER_ULONG(&(mpagent->itpend)); /* first read the interrupt pending MP_Agent register */ + + if (itpend & (MPA_INTN_ITMSG1 | MPA_INTN_ITMSG2)) { + + // + // reading the message register clears the interrupt from the MP Agent + // + + if (itpend & MPA_INTN_ITMSG1) { + msg_data = (READ_REGISTER_ULONG(&(mpagent->datamsg1)) >> 24); + if (msg_data == MPA_KERNEL_MESSAGE) { + KeIpiInterrupt(TrapFrame); + } else { + // remove this processor from the list of active processors + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->ActiveProcessor[PCR->Number]=0; + if (PCR->Number) { + + // call a firmware funtion to stop slave cpu's which will break the caches + + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->reinit_slave(); + + } else { + + HalpBootCpuRestart(); + } + } + } + + if (itpend & MPA_INTN_ITMSG2) { + msg_data = (READ_REGISTER_ULONG(&(mpagent->datamsg2)) >> 24); + KeUpdateRunTime(TrapFrame); + } + + HalpCheckSpuriousInt(0); + + return ; + } + + if ((itpend & MPA_INTN_INT_MASK) == 0) { + + ULONG snooper = READ_REGISTER_ULONG(&(mpagent->snooper)); + + // + // None of the MP Agent internal Interrupts was pending --> just return + // + + HalpCheckSpuriousInt(0); + + + return ; + } + + if (itpend & MPA_INTN_MPBERR) { + + // + // Fatal Error + // + + ULONG snooper, cpureg, tmp ; + + cpureg = READ_REGISTER_ULONG(&(mpagent->cpureg)); /* read the current value */ + cpureg &= ~(MPA_ENINT_MPBERR /* disable interrupt for MP_Agent fatal error */ + ); /* keep other fields */ + WRITE_REGISTER_ULONG(&(mpagent->cpureg), cpureg); // write the new value in the MP_Agent register / + snooper = READ_REGISTER_ULONG(&(mpagent->snooper)); // read the current snooper register value/ + + tmp = READ_REGISTER_ULONG(&(mpagent->snpadreg)); /* read the current value */ + snooper |= MPA_RSTSNPERR; /* reset this MP_Agent fatal error */ + WRITE_REGISTER_ULONG(&(mpagent->snooper), snooper); /* write the new value in the MP_Agent register */ + + if ((snooper & MPA_MSEQERR == MPA_RETRYERR) || (snooper & MPA_MSEQERR ==0)) { + snooper &= ~(MPA_RSTSNPERR); /* stop reseting this MP_Agent fatal error */ + WRITE_REGISTER_ULONG(&(mpagent->snooper), snooper); /* write the new value in the MP_Agent register */ + cpureg = READ_REGISTER_ULONG(&(mpagent->cpureg)); /* read the current value */ + cpureg |= (MPA_ENINT_MPBERR); /* enable interrupt for MP_Agent fatal error */ + WRITE_REGISTER_ULONG(&(mpagent->cpureg), cpureg); // write the new value in the MP_Agent register / + + } else { +#if DBG + DebugPrint(("MP_Agent fatal error : adresse=0x%x snooper=0x%x\n",tmp,snooper)); + DbgBreakPoint(); +#else + HalpDisableInterrupts(); // for the MATROX boards... + HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode + HalDisplayString("\n"); + HalpClearVGADisplay(); + HalpBugCheckNumber = 0; + HalDisplayString(HalpBugCheckMessage[0]); // "MP_Agent fatal error\n" + HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,snooper,tmp,0); +#endif + + } + + HalpCheckSpuriousInt(0); + + return ; + } + + if (itpend & MPA_INTN_ITMSG3) { + + + // + // reading the message register clears the interrupt from the MP Agent + // + + msg_data = (READ_REGISTER_ULONG(&(mpagent->datamsg3)) >> 24); + HalpCheckSpuriousInt(0); + + return ; + } +} + +ULONG +HalpGetMyAgent( + VOID + ) +{ + ULONG reg; + reg = READ_REGISTER_ULONG(&(mpagent->snooper)); /* read the current value */ + return( (reg & MPA_ADAGT_MASK) >> MPA_ADAGT_SHIFT); +} + + + +/* + * ====================================================================== + * + * NAME: mpa_check_spurious_intr + * + * PURPOSE: Fix a bug in the MP_Agent which sometimes make a bad + * update of the cause register. + * + * PARAMETERS: none + * + * RETURNS: = 0 no possible spurious interrupt + * 1 possible spurious interrupt + * + * ====================================================================== + */ +BOOLEAN HalpCheckSpuriousInt(ULONG mask) +{ + +ULONG itpend, causeit, pending; +ULONG cpureg, tempreg, reg; + + if ( HalpProcessorId != MPAGENT) { + return 0; + } + + + + itpend = READ_REGISTER_ULONG(&(mpagent->itpend)); /* read the interrupt pending MP_Agent register */ + + causeit = (itpend & MPA_OINTN_MASKGEN) >> MPA_OINTN_SHIFT; + pending = (itpend & MPA_INTN_MASKGEN ); + + if (causeit != pending) { + + /* + * Need a second filter for pending interrupt which don't take care + * of real enabled interrupt mask of cpureg. + */ + cpureg = READ_REGISTER_ULONG(&(mpagent->cpureg)); /* read interrupt enable mask for this cpu */ + + if (PCR->Prcb->Number == 0) { + if (HalpIsTowerPci && HalpIsMulti == 0) + pending &= ( + ((cpureg & (MPA_ENINT_SR_IP3 | MPA_ENINT_SR_IP6 | + MPA_ENINT_SR_IP7 )) >> MPA_ENINT_MASKSHIFT) + | + ((cpureg & (MPA_ENINT_ITMSG1 | + MPA_ENINT_ITMSG2 | + MPA_ENINT_ITMSG3 | + MPA_ENINT_MPBERR)) >> (MPA_ENINT_MASKSHIFT-1)) + ); + else + pending &= ( + ((cpureg & (MPA_ENINT_SR_IP3 | + MPA_ENINT_SR_IP7 )) >> MPA_ENINT_MASKSHIFT) + | + ((cpureg & (MPA_ENINT_ITMSG1 | + MPA_ENINT_ITMSG2 | + MPA_ENINT_ITMSG3 | + MPA_ENINT_MPBERR)) >> (MPA_ENINT_MASKSHIFT-1)) + ); + } else if (PCR->Prcb->Number == 1){ + if (HalpIsTowerPci){ + pending &= ( + ((cpureg & (MPA_ENINT_SR_IP6 | + MPA_ENINT_SR_IP7 )) >> MPA_ENINT_MASKSHIFT) + | + ((cpureg & (MPA_ENINT_ITMSG1 | + MPA_ENINT_ITMSG2 | + MPA_ENINT_ITMSG3 | + MPA_ENINT_MPBERR)) >> (MPA_ENINT_MASKSHIFT-1)) + ); + }else{ + pending &= ( + ((cpureg & (MPA_ENINT_SR_IP5 | + MPA_ENINT_SR_IP7 )) >> MPA_ENINT_MASKSHIFT) + | + ((cpureg & (MPA_ENINT_ITMSG1 | + MPA_ENINT_ITMSG2 | + MPA_ENINT_ITMSG3 | + MPA_ENINT_MPBERR)) >> (MPA_ENINT_MASKSHIFT-1)) + ); + } + } else { + pending &= ( + ((cpureg & MPA_ENINT_SR_IP7 ) >> MPA_ENINT_MASKSHIFT) + + | + ((cpureg & (MPA_ENINT_ITMSG1 | + MPA_ENINT_ITMSG2 | + MPA_ENINT_ITMSG3 | + MPA_ENINT_MPBERR)) >> (MPA_ENINT_MASKSHIFT-1)) + ); + + } + + if (causeit != pending) { + + /* + * There is sometimes an MP_Agent interrupt with values different in + * MPA_INTN_... = 0 and MPA_OINTN_.... + * That means : The cause register has been updated with a wrong value! + * We need to force a new update of the cause register to avoid looping + * on this interrupt until a new external interrupt happens. + */ + if (cpureg & MPA_INTCONF_SR_IP8) { + tempreg = (cpureg & (~MPA_INTCONF_SR_IP8)) | MPA_ENINT_SR_IP8; + } else { + tempreg = (cpureg | MPA_INTCONF_SR_IP8 | MPA_ENINT_SR_IP8); + } + + WRITE_REGISTER_ULONG(&(mpagent->cpureg), tempreg); // write the new value in the MP_Agent register / + + + WRITE_REGISTER_ULONG(&(mpagent->cpureg), cpureg); // Restore initial value + + + if (mask <= 1) { + + + + return 0; + } + + reg = HalpGetCauseRegister(); + if ( reg & mask ) { + + + return 0; + } else { + + + return 1; + } + } + } + + + + return 0; /* No possible spurious ! */ + +} + + diff --git a/private/ntos/nthals/halsnip/mips/mpagent.h b/private/ntos/nthals/halsnip/mips/mpagent.h new file mode 100644 index 000000000..650cb4d81 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/mpagent.h @@ -0,0 +1,594 @@ +// +// Defines for Access to the MP Agent +// this file can be used on assembly language files and C Files +// + +#ifndef _MPAGENT_H_ +#define _MPAGENT_H_ + + +#define MPA_BASE_ADDRESS 0xbffff000 /* Base to address the MP_Agent */ +#define MPA_BOOT_MESSAGE 6 /* to start the other processors */ +#define MPA_KERNEL_MESSAGE 10 /* kernel requested IPI */ +#define MPA_TIMER_MESSAGE 11 /* timer interrupt */ +#define MPA_RESTART_MESSAGE 12 /* restart requested */ + +// +// define relative offsets of the MP Agent registers +// (little endian mode) +// + +#define MPA_cpureg 0x000 // (0x00 * 8) configuration cpu register +#define MPA_cpuda1reg 0x008 // (0x01 * 8) general register +#define MPA_msgdata 0x010 // (0x02 * 8) data for message passing +#define MPA_msgstatus 0x018 // (0x03 * 8) message status +#define MPA_snooper 0x020 // (0x04 * 8) snooper configuration register +#define MPA_tagreg 0x028 // (0x05 * 8) tag ram R/W index register +#define MPA_snpadreg 0x030 // (0x06 * 8) adress of first MBus fatal error +#define MPA_itpend 0x038 // (0x07 * 8) Interrupt register +#define MPA_datamsg1 0x040 // (0x08 * 8) data message register 1 +#define MPA_datamsg2 0x048 // (0x09 * 8) data message register 2 +#define MPA_datamsg3 0x050 // (0x0a * 8) data message register 3 +#define MPA_lppreg0 0x058 // (0x0b * 8) LPP register cpu 0 +#define MPA_lppreg1 0x060 // (0x0c * 8) LPP register cpu 1 +#define MPA_lppreg2 0x068 // (0x0d * 8) LPP register cpu 2 +#define MPA_lppreg3 0x070 // (0x0e * 8) LPP register cpu 3 +#define MPA_tagram 0x078 // (0x0f * 8) tag ram R/W register +#define MPA_crefcpt 0x080 // (0x10 * 8) cpu general read counter register +#define MPA_ctarcpt 0x088 // (0x11 * 8) cpu programmable access counter +#define MPA_srefcpt 0x090 // (0x12 * 8) snooper general read counter reg. +#define MPA_starcpt 0x098 // (0x13 * 8) snooper programmable accesscounter +#define MPA_linkreg 0x0a0 // (0x14 * 8) link register +#define MPA_software1 0x0a8 // (0x15 * 8) software register1 +#define MPA_msgaddress 0x0b0 // (0x16 * 8) address message register +#define MPA_mem_operator 0x0b8 // (0x17 * 8) operator internal burst register +#define MPA_software2 0x0c0 // (0x18 * 8) software register2 + + +/* +---------------------------+ */ +/* ! cpureg register (0x00) ! */ +/* +---------------------------+ */ +/* + + The CPUREG Register (LOW-PART) , which has the following bits: + + 15 14 13 12 11 10 9 8 | 7 6 5 4 3 2 1 0 + +---------------|---------------|---------------|---------------+ + | ED| ED| ED| | MI| MI| MI| EI| EI| EI| EI| EI| EI| R | 1 | 0 | 0 Low Activ; 1 High activ; + +---------------|---------------+---------------|---------------+ + + + + |__________ enable shared 1-> TagCopy for S + |_____________ enable message sending + |_________________ reserved + |_____________________ enable external Interrupts + |________________________ enable external Interrupts + |____________________________ enable external Interrupts + |________________________________ enable external Interrupts + |____________________________________ enable external Interrupts + + |__________________________________________ enable external Interrupts + |______________________________________________ enable Message Reg. Int. + |__________________________________________________ enable Message Reg. Int. + |______________________________________________________ enable Message Reg. Int. + |__________________________________________________________ + |______________________________________________________________ Edge Config for Interrupts + |__________________________________________________________________ Edge Config for Interrupts + |______________________________________________________________________ Edge Config for Interrupts + + + The CPUREG Register (HIGH-PART), which has the following bits: + + + + 31 30 29 28 27 26 25 24| 23 22 21 20 19 18 17 16 + +---------------|---------------|---------------|---------------+ + | 1 | 1 | 1 | 1 | 1 | MA| MA| MA| MA| MA| MA| MA| ED| ED| ED| ED| 0 Low Activ; 1 High activ; + +---------------|---------------+---------------|---------------+ + + + + |_________ Edge Config for Interrupts + |_____________ Edge Config for Interrupts + |________________ Edge Config for Interrupts + |____________________ Edge Config for Interrupts + |________________________ Interrupt Mask on external Request + |____________________________ Interrupt Mask on external Request + |________________________________ Interrupt Mask on external Request + |____________________________________ Interrupt Mask on external Request + + |__________________________________________ Interrupt Mask on external Request + |______________________________________________ Interrupt Mask on external Request + |__________________________________________________ Interrupt Mask on external Request + |______________________________________________________ maximal Retry Count on MP-Bus + |__________________________________________________________ maximal Retry Count on MP-Bus + |______________________________________________________________ maximal Retry Count on MP-Bus + |__________________________________________________________________ maximal Retry Count on MP-Bus + |______________________________________________________________________ maximal Retry Count on MP-Bus + +*/ + +#define MPA_ENSHARED 0x00000001 /* (0) If the MP_Agent has not the data in + * exclusif state, the MP_Agent forces + * the data to shared state for all + * coherent access. + * + * (1) If no other MP_agent has the data + * in exclusif state, the requester + * can put the data in share or exclusif + * state. + */ + +#define MPA_ENSENDMSG 0x00000002 /* (1) 0 -> disable message passing + * 1 -> enable message passing + */ + +#define MPA_ENINT_MASK 0x00001ffc /* (12:2) enable interrupt mask */ +#define MPA_ENINT_MASKSHIFT 3 /* shift for enable interrupt mask */ +#define MPA_ENINT_SR_IP3 0x00000008 /* (3) enable external interrupt SR_IP3 */ +#define MPA_ENINT_SR_IP4 0x00000010 /* (4) enable external interrupt SR_IP4 */ +#define MPA_ENINT_SR_IP5 0x00000020 /* (5) enable external interrupt SR_IP5 */ +#define MPA_ENINT_SR_IP6 0x00000040 /* (6) enable external interrupt SR_IP6 */ +#define MPA_ENINT_SR_IP7 0x00000080 /* (7) enable external interrupt SR_IP7 */ +#define MPA_ENINT_SR_IP8 0x00000100 /* (8) enable external interrupt SR_IP8 */ +#define MPA_ENINT_ITMSG1 0x00000200 /* (9) enable interrupt message1 register */ +#define MPA_ENINT_ITMSG2 0x00000400 /* (10) enable interrupt message2 register */ +#define MPA_ENINT_ITMSG3 0x00000800 /* (11) enable interrupt message3 register */ +#define MPA_ENINT_MPBERR 0x00001000 /* (12) enable interrupt MP_Agent fatal error */ + +#define MPA_INTCONF_MASK 0x000fe000 /* (19:13) select interrupt level + * 0 -> falling + * 1 -> raising */ +#define MPA_INTCONF_SR_IP3 0x00002000 /* (13) select raising mode for SR_IP3 */ +#define MPA_INTCONF_SR_IP4 0x00004000 /* (14) select raising mode for SR_IP4 */ +#define MPA_INTCONF_SR_IP5 0x00008000 /* (15) select raising mode for SR_IP5 */ +#define MPA_INTCONF_SR_IP6 0x00010000 /* (16) select raising mode for SR_IP6 */ +#define MPA_INTCONF_SR_IP7 0x00020000 /* (17) select raising mode for SR_IP7 */ +#define MPA_INTCONF_SR_IP8 0x00040000 /* (18) select raising mode for SR_IP8 */ +#define MPA_INTCONF_SR_NMI 0x00080000 /* (19) select raising mode for SR_NMI */ + +#define MPA_INTMSK 0x07f00000 /* (26:20) mask sent during external request stage */ + +#define MPA_MAXRTY_MASK 0xf8000000 /* (31:27) mask for maximum number of retry on + * INV / UPD / MESS / RD_COH */ + +/* +---------------------------+ */ +/* ! cpuda1reg register (0x01) ! */ +/* +---------------------------+ */ +/* + The CPU1REG Register (LOW-PART) , which has the following bits: + + 15 14 13 12 11 10 9 8 | 7 6 5 4 3 2 1 0 + +---------------|---------------|---------------|---------------+ + | SS| SS| TI| 1 | DP| DP| R | R | R | R | R | R | R | R | R | R | 0 Low Activ; 1 High activ; + +---------------|---------------+---------------|---------------+ + + + + |_________ reserved + |_____________ reserved + |________________ reserved + |____________________ reserved + |________________________ reserved + |____________________________ reserved + |________________________________ reserved + |____________________________________ reserved + |__________________________________________ reserved + |______________________________________________ reserved + |__________________________________________________ CPU Data Pattern + |______________________________________________________ CPU Data Pattern + |__________________________________________________________ Int. Update Policy 0 - direct + |______________________________________________________________ Test Interrupts + |__________________________________________________________________ Cpu Port Statistics + |______________________________________________________________________ Cpu Port Statistics + + + The CPU1REG Register (HIGH-PART), which has the following bits: + + 31 30 29 28 27 26 25 24| 23 22 21 20 19 18 17 16 + +---------------|---------------|---------------|---------------+ + | R | R | R | R | R | R | R | R | R | R | R | IS| IS| IS| 1 | SS| 0 Low Activ; 1 High activ; + +---------------|---------------+---------------|---------------+ + + + + |_________ Cpu Port Statistics + |_____________ Enable Read Anticipate mode + |________________ Select Interrupt for Internal Ints + |____________________ Select Interrupt for Internal Ints + |________________________ Select Interrupt for Internal Ints + |____________________________ reserved + |________________________________ reserved + |____________________________________ reserved + + |__________________________________________ reserved + |______________________________________________ reserved + |__________________________________________________ reserved + |______________________________________________________ reserved + |__________________________________________________________ reserved + |______________________________________________________________ reserved + |__________________________________________________________________ reserved + |______________________________________________________________________ reserved + +*/ + +#define MPA_CPURDPAT_MASK 0x00000c00 /* (11:10) number of wait-state between 2 double + * cpu reads. */ +#define MPA_CPURDPAT_DD 0x00000000 /* 0 : dd */ +#define MPA_CPURDPAT_DDX 0x00000400 /* 1 : dd. */ +#define MPA_CPURDPAT_DDXX 0x00000800 /* 2 : dd.. */ +#define MPA_CPURDPAT_DXDX 0x00000c00 /* 3 : d.d. */ + +#define MPA_ENDIRECT 0x00001000 /* (12) 0 send interrupt to all MP_Agent + * 1 use LPP mechanism to dispatch interrupt + */ + +#define MPA_ENTESTIT 0x00002000 /* (13) 0 disable test mode (interrupts from MPBus) + * 1 enable test mode (interrupts from INTCONF(6:0)) + */ + +#define MPA_CPUSELSTAT_MASK 0x0001c000 /* (16:14) select programmable mode for cpu + * access + */ + +#define MPA_ENRDANT 0x00020000 /* (17) 0 disable overlapping memory/MP_Agent + * + * 1 enable overlapping memory/MP_Agent + * The Tag copy checking is done concurently + * with memory access. The memory must support + * the 'read abort' command (not supported + * by current Asic chipset rev.0). + */ + +#define MPA_SELITI_MASK 0x001c0000 /* (20:18) define routage for internal interrupts */ +#define MPA_SELITI_SR_IP3 0x00000000 /* Internal interrupts go on SR_IP3 */ +#define MPA_SELITI_SR_IP4 0x00040000 /* Internal interrupts go on SR_IP4 */ +#define MPA_SELITI_SR_IP5 0x00080000 /* Internal interrupts go on SR_IP5 */ +#define MPA_SELITI_SR_IP6 0x000c0000 /* Internal interrupts go on SR_IP6 */ +#define MPA_SELITI_SR_IP7 0x00100000 /* Internal interrupts go on SR_IP7 */ +#define MPA_SELITI_SR_IP8 0x00140000 /* Internal interrupts go on SR_IP8 */ + +/* +---------------------------+ */ +/* ! msgstatus register (0x03) ! */ +/* +---------------------------+ */ + +/* message passing status register */ + +#define MPA_VALSTAT 0x00000001 /* (0) 0 -> status is invalid + * 1 -> status is valid */ +// +// if (MPA_VALSTAT != 0) +// + +#define MPA_SENDMSG 0x00000002 /* (1) 1 -> message not acknowledged by MPBus */ +#define MPA_ERRMSG 0x00000004 /* (2) 0 -> message has been acknowledged + * 1 -> at least one MP_Agent has refused */ +#define MPA_BUSY 0x00000008 +#define MPA_ADERR_MASK 0x000000f0 /* (7:4) list of refusing processor(s) */ +#define MPA_ADERR_SHIFT 0x4 + + +/* +---------------------------+ */ +/* ! snooper register (0x04) ! */ +/* +---------------------------+ */ + +/* + The SNOOPER Register (LOW-PART), which has the following bits: + + 15 14 13 12 11 10 9 8 | 7 6 5 4 3 2 1 0 + +---------------|---------------|---------------|---------------+ + | 1 | R | R | R | R | - | - | - | 1 | 1 | 1 | - | - | R | R | 1 | 0 Low Activ; 1 High activ; + +---------------|---------------+---------------|---------------+ + + + + |_________ enable Message receive + |_____________ reserved + |________________ reserved + |____________________ LineSize + |________________________ LineSize + |____________________________ Three/ Two Party + |________________________________ enable Read+Link + |____________________________________ enable Coherency + + |__________________________________________ MP Statistics + |______________________________________________ MP Statistics + |__________________________________________________ MP Statistics + |______________________________________________________ reserved + |__________________________________________________________ reserved + |______________________________________________________________ reserved + |__________________________________________________________________ reserved + |______________________________________________________________________ FATAL INTERRUPT inactive + + + The SNOOPER Register (HIGH-PART), which has the following bits: + + 31 30 29 28 27 26 25 24| 23 22 21 20 19 18 17 16 + +---------------|---------------|---------------|---------------+ + | 1 | 1 | 1 | 1 | 1 | R | R | R | R | R | M | M | M | C | C | C | 0 Low Activ; 1 High activ; + +---------------|---------------+---------------|---------------+ + + + + |_________ Cderrtag TagSeq direct error code + |_____________ Cderrtag + |________________ Cderrtag + |____________________ Mderrtag SnpTagSeq memo Error code + |________________________ Mderrtag + |____________________________ Mderrtag + |________________________________ reserved + |____________________________________ reserved + + |__________________________________________ reserved + |______________________________________________ reserved + |__________________________________________________ reserved + |______________________________________________________ Agent Address + |__________________________________________________________ Agent Address + |______________________________________________________________ seq. cpu error + |__________________________________________________________________ tag seq. error + |______________________________________________________________________ ext. seq. error + +*/ + +#define MPA_ENRCVMESS 0x00000001 /* (0) 0 -> disable message receiving + * 1 -> enable message receiving */ + +#define MPA_LSIZE_MASK 0x00000018 /* (4:3) secondary linesize mask */ +#define MPA_LSIZE16 0x00000000 /* secondary linesize = 16 bytes */ +#define MPA_LSIZE32 0x00000008 /* secondary linesize = 32 bytes */ +#define MPA_LSIZE64 0x00000010 /* secondary linesize = 64 bytes */ +#define MPA_LSIZE128 0x00000018 /* secondary linesize = 128 bytes */ + +/* NOTE: MP_Agent doesn't support linesize greater than 64 bytes !! */ + +#define MPA_DISTPARTY 0x00000020 /* (5) 0 -> enable three-party mode + * MP_Agent requester/MP_Agent target + * + memory (for update) + * + * 1 -> disable three-party mode + * MP_Agent requester/MP_Agent target + */ + +#define MPA_ENLINK 0x00000040 /* (6) 0 -> The cpu read and link command is + * disabled. + * 1 -> The cpu read and link command is + * enabled. + */ + +#define MPA_ENCOHREQ 0x00000080 /* (7) 0 -> disable sending external request + * for coherency to cpu by his MP_Agent + * 1 -> enable sending external request + * for coherency to cpu by his MP_Agent + */ + +#define MPA_SNPSELSTAT_MASK 0x00000700 /* (10:8) select programmable mode for snooper + * access + */ + +#define MPA_RSTSNPERR 0x00008000 /* (15) 1 -> reset all MP bus fatal error + * + * 0 -> enable new fatal error on MP bus + * sent by interrupt. + */ + +#define MPA_CDERRTAG 0x00070000 /* (18:16) (Read only) error code */ + +#define MPA_MCDERRTAG 0x00380000 /* (21:19) (Read only) error code */ + +#define MPA_MCDERREXT 0x00c00000 /* (23:22) (Read only) error code */ + +#define MPA_ADAGT_MASK 0x18000000 /* (28:27) (Read only) MP_Agent address mask */ +#define MPA_ADAGT_SHIFT 27 /* shift address agent value */ + +#define MPA_MSEQERR 0xe0000000 /* (31:29) (Read only) error code */ +#define MPA_RETRYERR 0x20000000 /* (31:29) (Read only) error code */ + + +/* +---------------------------+ */ +/* ! itpend register (0x07) ! */ +/*+---------------------------+ */ + +/* + The Interrupt Pending Register (LOW-PART) , which has the following bits: + + 15 14 13 12 11 10 9 8 | 7 6 5 4 3 2 1 0 + +---------------|---------------|---------------|---------------+ + | UE| UE| UE| UE| R | F | M | M | M | R | E | E | E | E | E | E | 0 Low Activ; 1 High activ; + +---------------|---------------+---------------|---------------+ + + + + |_________ pending external Interrupts + |_____________ pending external Interrupts + |________________ pending external Interrupts + |____________________ pending external Interrupts + |________________________ pending external Interrupts + |____________________________ pending external Interrupts + |________________________________ reserved + |____________________________________ Message Register 1 + + |__________________________________________ Message Register 2 + |______________________________________________ Message Register 3 + |__________________________________________________ FATAL MP Agent Error + |______________________________________________________ reserved + |__________________________________________________________ last updated external State + |______________________________________________________________ last updated external State + |__________________________________________________________________ last updated external State + |______________________________________________________________________ last updated external State + + The Interrupt Pending Register (HIGH-PART), which has the following bits: + + 31 30 29 28 27 26 25 24| 23 22 21 20 19 18 17 16 + +---------------|---------------|---------------|---------------+ + | R | R | R | R | R | R | R | R | R | UF| UM| UM| UM| R | UE| UE| 0 Low Activ; 1 High activ; + +---------------|---------------+---------------|---------------+ + + + + |_________ last updated external State + |_____________ last updated external State + |________________ reserved + |____________________ last updated Message State + |________________________ last updated Message State + |____________________________ last updated Message State + |________________________________ last updated FATAL E State + |____________________________________ reserved + + |__________________________________________ reserved + |______________________________________________ reserved + |__________________________________________________ reserved + |______________________________________________________ reserved + |__________________________________________________________ reserved + |______________________________________________________________ reserved + |__________________________________________________________________ reserved + |______________________________________________________________________ reserved + +*/ + +/* external interrupts */ +#define MPA_INTN_MASKGEN 0x000007ff /* (10:0) pending general interrupt mask */ +#define MPA_INTN_EXT_MASK 0x0000003f /* (5:0) pending external interrupt mask */ +#define MPA_INTN_SR_IP3 0x00000001 /* (0) pending external interrupt SR_IP3 */ +#define MPA_INTN_SR_IP4 0x00000002 /* (1) pending external interrupt SR_IP4 */ +#define MPA_INTN_SR_IP5 0x00000004 /* (2) pending external interrupt SR_IP5 */ +#define MPA_INTN_SR_IP6 0x00000008 /* (3) pending external interrupt SR_IP6 */ +#define MPA_INTN_SR_IP7 0x00000010 /* (4) pending external interrupt SR_IP7 */ +#define MPA_INTN_SR_IP8 0x00000020 /* (5) pending external interrupt SR_IP8 */ + +/* internal interrupts */ +#define MPA_INTN_ITNMI 0x00000040 /* (6) unused */ +#define MPA_INTN_ITMSG1 0x00000080 /* (7) pending interrupt message1 register */ +#define MPA_INTN_ITMSG2 0x00000100 /* (8) pending interrupt message2 register */ +#define MPA_INTN_ITMSG3 0x00000200 /* (9) pending interrupt message3 register */ +#define MPA_INTN_MPBERR 0x00000400 /* (10) pending interrupt MP_Agent fatal error */ +/* pending internal interrupts mask */ +#define MPA_INTN_INT_MASK (MPA_INTN_ITNMI | \ + MPA_INTN_ITMSG1 | \ + MPA_INTN_ITMSG2 | \ + MPA_INTN_ITMSG3 | \ + MPA_INTN_MPBERR) + +/* old interrupts written in the processor cause register */ + +/* external interrupts */ +#define MPA_OINTN_MASKGEN 0x007ff000 /* (22:12) old general interrupt mask */ +#define MPA_OINTN_SHIFT 12 /* shift to compare to pending interrupt */ +#define MPA_OINTN_MASK 0x0003f000 /* (17:12) old external interrupt mask */ +#define MPA_OINTN_SR_IP3 0x00001000 /* (12) old external interrupt SR_IP3 */ +#define MPA_OINTN_SR_IP4 0x00002000 /* (13) old external interrupt SR_IP4 */ +#define MPA_OINTN_SR_IP5 0x00004000 /* (14) old external interrupt SR_IP5 */ +#define MPA_OINTN_SR_IP6 0x00008000 /* (15) old external interrupt SR_IP6 */ +#define MPA_OINTN_SR_IP7 0x00010000 /* (16) old external interrupt SR_IP7 */ +#define MPA_OINTN_SR_IP8 0x00020000 /* (17) old external interrupt SR_IP8 */ + +/* internal interrupts */ +#define MPA_OINTN_ITNMI 0x00040000 /* (18) unused */ +#define MPA_OINTN_ITMSG1 0x00080000 /* (19) old interrupt message1 register */ +#define MPA_OINTN_ITMSG2 0x00100000 /* (20) old interrupt message2 register */ +#define MPA_OINTN_ITMSG3 0x00200000 /* (21) old interrupt message3 register */ +#define MPA_OINTN_MPBERR 0x00400000 /* (22) old interrupt MP_Agent fatal error */ + + +/* +---------------------------+ */ +/* ! msgaddress register(0x16) ! */ +/* +---------------------------+ */ + +/* Message address for message passing */ + +#define MPA_CPUTARGET_MASK 0x0000000f /* (3:0) target cpu mask */ +#define MPA_CPUTARGET_ALL 0x0000000f /* cpu target : all */ +#define MPA_CPUTARGET_CPU0 0x00000001 /* cpu target : 0 */ +#define MPA_CPUTARGET_CPU1 0x00000002 /* cpu target : 1 */ +#define MPA_CPUTARGET_CPU2 0x00000004 /* cpu target : 2 */ +#define MPA_CPUTARGET_CPU3 0x00000008 /* cpu target : 3 */ + +#define MPA_REGTARGET_MASK 0x000001f0 /* (8:4) target register */ +#define MPA_REGTARGET_MSG1 0x00000080 /* msg1reg target register */ +#define MPA_REGTARGET_MSG2 0x00000090 /* msg2reg target register */ +#define MPA_REGTARGET_MSG3 0x000000a0 /* msg3reg target register */ + +#define MPA_ENMSGLPP 0x00000200 /* (9) 0 disable LPP mode for message passing */ + +/* +---------------------------+ */ +/* ! mem_operator reg. (0x17) ! */ +/* +---------------------------+ */ + +/* For fake read on a 4Mb segment. Used for cache replace functions */ + +#define MPA_OP_ENABLE 0x00000001 /* (0) 0 disable operator (address invalid) + * 1 enable operator (address valid) + */ + +#define MPA_OP_ADDR_MASK 0xffc00000 /* (31:22) base physical address of a 4Mb kseg0 + * reserved segment (4Mb == 0x00400000). + */ + + +#define MPA_TAGREG_ADDR_MASK 0x003ffff0 +#define MPA_TR_STATE_MASK 0x00000003 +#define MPA_TR_NOCOHERENT 0x00000000 +/* + * Number of retries before sending a fatal error + */ +#define MPA_MSG_RETRY 10 + +typedef struct _mp_agent{ + + /* Register Register + * name number offset description + * ---------- ---- ------ --------------------------------- */ + ULONG cpureg; /* 0x00 0x000 configuration cpu register */ + ULONG invalid_0; + ULONG cpuda1reg; /* 0x01 0x008 general register */ + ULONG invalid_1; + ULONG msgdata; /* 0x02 0x010 data for message passing */ + ULONG invalid_2; + ULONG msgstatus; /* 0x03 0x018 message status */ + ULONG invalid_3; + ULONG snooper; /* 0x04 0x020 snooper configuration register */ + ULONG invalid_4; + ULONG tagreg; /* 0x05 0x028 tag ram R/W index register */ + ULONG invalid_5; + ULONG snpadreg; /* 0x06 0x030 adress of first MBus fatal error */ + ULONG invalid_6; + ULONG itpend; /* 0x07 0x038 Interrupt register */ + ULONG invalid_7; + ULONG datamsg1; /* 0x08 0x040 data message register 1 */ + ULONG invalid_8; + ULONG datamsg2; /* 0x09 0x048 data message register 2 */ + ULONG invalid_9; + ULONG datamsg3; /* 0x0a 0x050 data message register 3 */ + ULONG invalid_a; + ULONG lppreg0; /* 0x0b 0x058 LPP register cpu 0 */ + ULONG invalid_b; + ULONG lppreg1; /* 0x0c 0x060 LPP register cpu 1 */ + ULONG invalid_c; + ULONG lppreg2; /* 0x0d 0x068 LPP register cpu 2 */ + ULONG invalid_d; + ULONG lppreg3; /* 0x0e 0x070 LPP register cpu 3 */ + ULONG invalid_e; + ULONG tagram; /* 0x0f 0x078 tag ram R/W register */ + ULONG invalid_f; + ULONG crefcpt; /* 0x10 0x080 cpu general read counter register */ + ULONG invalid_10; + ULONG ctarcpt; /* 0x11 0x088 cpu programmable access counter */ + ULONG invalid_11; + ULONG srefcpt; /* 0x12 0x090 snooper general read counter reg. */ + ULONG invalid_12; + ULONG starcpt; /* 0x13 0x098 snooper programmable accesscounter*/ + ULONG invalid_13; + ULONG linkreg; /* 0x14 0x0a0 link register */ + ULONG invalid_14; + ULONG software1; /* 0x15 0x0a8 software register1 */ + ULONG invalid_15; + ULONG msgaddress; /* 0x16 0x0b0 address message register */ + ULONG invalid_16; + ULONG mem_operator; /* 0x17 0x0b8 operator internal burst register */ + ULONG invalid_17; + ULONG software2; /* 0x18 0x0c0 software register2 */ +}MP_AGENT, *PMP_AGENT; + +#define mpagent ((volatile PMP_AGENT) MPA_BASE_ADDRESS) // mpagent address + +#endif diff --git a/private/ntos/nthals/halsnip/mips/orcache.s b/private/ntos/nthals/halsnip/mips/orcache.s new file mode 100644 index 000000000..bf3024fe7 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/orcache.s @@ -0,0 +1,561 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/orcache.s,v 1.3 1996/02/23 17:55:12 pierre Exp $") +// TITLE("Cache Flush") +//++ +// +// Copyright (c) 1991-1993 Microsoft Corporation +// +// Module Name: +// +// orcache.s +// +// Abstract: +// +// This module implements the code necessary for cache operations on +// R4600 orion Machines. +// +// Environment: +// +// Kernel mode only. +// +//-- + +#include "halmips.h" +#include "SNIdef.h" + +#define ORION_REPLACE 0x17c00000 + +// +// some bitmap defines to display cache activities via the LED's +// in the SNI RM machines +// + +#define SWEEP_DCACHE 0xc0 // 1100 0000 +#define FLUSH_DCACHE_PAGE 0x80 // 1000 0000 +#define PURGE_DCACHE_PAGE 0x40 // 0100 0000 +#define ZERO_PAGE 0x0c // 0000 1100 + +#define SWEEP_ICACHE 0x30 // 0011 0000 +#define PURGE_ICACHE_PAGE 0x10 // 0001 0000 + +// +// Define cache operations constants. +// + +#define COLOR_BITS (7 << PAGE_SHIFT) // color bit (R4000 - 8kb cache) +#define COLOR_MASK (0x7fff) // color mask (R4000 - 8kb cache) +#define FLUSH_BASE 0xfffe0000 // flush base address +#define PROTECTION_BITS ((1 << ENTRYLO_V) | (1 << ENTRYLO_D) ) // + + + SBTTL("Flush Data Cache Page") +//++ +// +// VOID +// HalpFlushDcachePageOrion ( +// IN PVOID Color, +// IN ULONG PageFrame, +// IN ULONG Length +// ) +// +// Routine Description: +// +// This function flushes (cache replace) up to a page of data +// from the secondary data cache. (primary cache is already processed) +// +// Arguments: +// +// Color (a0) - Supplies the starting virtual address and color of the +// data that is flushed. +// +// PageFrame (a1) - Supplies the page frame number of the page that +// is flushed. +// +// Length (a2) - Supplies the length of the region in the page that is +// flushed. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpFlushDcachePageOrion) + +#if DBG + + lw t0,KeDcacheFlushCount // get address of dcache flush count + lw t1,0(t0) // increment the count of flushes + addu t1,t1,1 // + sw t1,0(t0) // store result + +#endif + +15: DISABLE_INTERRUPTS(t5) // disable interrupts + + .set noreorder + .set noat + +// +// Flush the secondary data caches => cache replace. +// + + .set noreorder + .set noat +40: and a0,a0,PAGE_SIZE -1 // PageOffset + sll t7,a1,PAGE_SHIFT // physical address + lw t4,KiPcr + PcSecondLevelDcacheFillSize(zero) // get 2nd fill size + or t0,t7,a0 // physical address + offset + subu t6,t4,1 // compute block size minus one + and t7,t0,t6 // compute offset in block + addu a2,a2,t6 // round up to next block + addu a2,a2,t7 // + nor t6,t6,zero // complement block size minus one + and a2,a2,t6 // truncate length to even number + beq zero,a2,60f // if eq, no blocks to flush + and t8,t0,t6 // compute starting virtual address + addu t9,t8,a2 // compute ending virtual address + subu t9,t9,t4 // compute ending loop address + + li a3,ORION_REPLACE // get base flush address + lw t0,KiPcr + PcSecondLevelDcacheSize(zero) // get cache size + add t0,t0,-1 // mask of the cache size + + .set noreorder + .set noat + +50: and t7,t8,t0 // offset + addu t7,t7,a3 // physical address + offset + lw zero,0(t7) // load Cache -> Write back old Data + bne t8,t9,50b // if ne, more blocks to invalidate + addu t8,t8,t4 // compute next block address (+Linesize) + +60: ENABLE_INTERRUPTS(t5) // enable interrupts + + j ra // return + + .end HalpFlushDcachePageOrion + + + SBTTL("Purge Instruction Cache Page") +//++ +// +// VOID +// HalpPurgeIcachePageOrion ( +// IN PVOID Color, +// IN ULONG PageFrame, +// IN ULONG Length +// ) +// +// Routine Description: +// +// This function purges (hit/invalidate) up to a page of data from the +// instruction cache. +// +// Arguments: +// +// Color (a0) - Supplies the starting virtual address and color of the +// data that is purged. +// +// PageFrame (a1) - Supplies the page frame number of the page that +// is purged. +// +// Length (a2) - Supplies the length of the region in the page that is +// purged. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpPurgeIcachePageOrion) + +#if DBG + + lw t0,KeIcacheFlushCount // get address of icache flush count + lw t1,0(t0) // increment the count of flushes + addu t1,t1,1 // + sw t1,0(t0) // store result + +#endif + + +15: DISABLE_INTERRUPTS(t5) // disable interrupts + + .set noreorder + .set noat + +// +// Flush the secondary data caches => cache replace. +// + + .set noreorder + .set noat +40: and a0,a0,PAGE_SIZE -1 // PageOffset + sll t7,a1,PAGE_SHIFT // physical address + lw t4,KiPcr + PcSecondLevelIcacheFillSize(zero) // get 2nd fill size + beq t4,zero,60f + or t0,t7,a0 // physical address + offset + subu t6,t4,1 // compute block size minus one + and t7,t0,t6 // compute offset in block + addu a2,a2,t6 // round up to next block + addu a2,a2,t7 // + nor t6,t6,zero // complement block size minus one + and a2,a2,t6 // truncate length to even number + beq zero,a2,60f // if eq, no blocks to flush + and t8,t0,t6 // compute starting virtual address + addu t9,t8,a2 // compute ending virtual address + subu t9,t9,t4 // compute ending loop address + + li a3,ORION_REPLACE // get base flush address + lw t0,KiPcr + PcSecondLevelIcacheSize(zero) // get cache size + add t0,t0,-1 // mask of the cache size + +50: and t7,t8,t0 // offset + addu t7,t7,a3 // physical address + offset + lw zero,0(t7) // load Cache -> Write back old Data + bne t8,t9,50b // if ne, more blocks to invalidate + addu t8,t8,t4 // compute next block address (+Linesize) + +60: ENABLE_INTERRUPTS(t5) // enable interrupts + + j ra // return + + .end HalpPurgeIcachePageOrion + + + SBTTL("Sweep Data Cache") +//++ +// +// VOID +// HalpSweepDcacheOrion ( +// VOID +// ) +// +// Routine Description: +// +// This function sweeps (index/writeback/invalidate) the entire data cache. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpSweepDcacheOrion) + +#if DBG + + lw t0,KeDcacheFlushCount // get address of dcache flush count + lw t1,0(t0) // increment the count of flushes + addu t1,t1,1 // + sw t1,0(t0) // store result +#endif + + .set at + .set reorder + + DISABLE_INTERRUPTS(t3) // disable interrupts + + .set noreorder + .set noat + +// +// Sweep the primary data cache. +// + + lw t0,KiPcr + PcFirstLevelDcacheSize(zero) // get data cache size + lw t1,KiPcr + PcFirstLevelDcacheFillSize(zero) // get block size + li a0,KSEG0_BASE // set starting index value + +// +// the size is configured on SNI machines as 16KB +// we invalidate in both sets - so divide the configured size by 2 +// + + srl t0,t0,1 + + addu a1,a0,t0 // compute ending cache address + subu a1,a1,t1 // compute ending block address + +10: + cache INDEX_WRITEBACK_INVALIDATE_D,0(a0) // writeback/invalidate on index + cache INDEX_WRITEBACK_INVALIDATE_D,8192(a0) + + bne a0,a1,10b // if ne, more to invalidate + addu a0,a0,t1 // compute address of next block + +// +// sweep secondary cache +// + + lw t0,KiPcr + PcSecondLevelDcacheSize(zero) // get data cache size + lw t1,KiPcr + PcSecondLevelDcacheFillSize(zero) // get block size + + li a0,ORION_REPLACE // starting address + addu a1,a0,t0 // compute ending cache address + subu a1,a1,t1 // compute ending block address + +25: + lw zero,0(a0) + bne a0,a1,25b // if ne, more to invalidate + addu a0,a0,t1 // compute address of next block + + ENABLE_INTERRUPTS(t3) // enable interrupts + + .set at + .set reorder + + j ra // return + + + .end HalpSweepDcacheMulti + + + SBTTL("Sweep Instruction Cache") +//++ +// +// VOID +// HalpSweepIcacheOrion ( +// VOID +// ) +// +// Routine Description: +// +// This function sweeps (index/invalidate) the entire instruction cache. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpSweepIcacheOrion) + +#if DBG + + lw t0,KeIcacheFlushCount // get address of icache flush count + lw t1,0(t0) // increment the count of flushes + addu t1,t1,1 // + sw t1,0(t0) // store result +#endif +// +// Sweep the secondary instruction cache. +// + + .set noreorder + .set noat + + DISABLE_INTERRUPTS(t3) // disable interrupts + + .set noreorder + .set noat + +// +// sweep secondary cache +// + + lw t0,KiPcr + PcSecondLevelIcacheSize(zero) // get instruction cache size + lw t1,KiPcr + PcSecondLevelIcacheFillSize(zero) // get fill size + beq zero,t0,20f // if eq, no second level cache + li a0,ORION_REPLACE // set starting index value + addu a1,a0,t0 // compute ending cache address + subu a1,a1,t1 // compute ending block address + +10: lw zero,0(a0) + bne a0,a1,10b // if ne, more to invalidate + addu a0,a0,t1 // compute address of next block + +// +// Sweep the primary instruction cache. +// + +20: lw t0,KiPcr + PcFirstLevelIcacheSize(zero) // get instruction cache size + lw t1,KiPcr + PcFirstLevelIcacheFillSize(zero) // get fill size + li a0,KSEG0_BASE // set starting index value + +// +// the size is configured on SNI machines as 16KB +// we invalidate in both sets - so divide the configured size by 2 +// + + srl t0,t0,1 + addu a1,a0,t0 // compute ending cache address + subu a1,a1,t1 // compute ending block address + +// +// Sweep the primary instruction cache. +// + +30: cache INDEX_INVALIDATE_I,0(a0) // invalidate cache line + cache INDEX_INVALIDATE_I,8192(a0) + + bne a0,a1,30b // if ne, more to invalidate + addu a0,a0,t1 // compute address of next block + .set at + .set reorder + +20: ENABLE_INTERRUPTS(t3) // enable interrupts + + .set at + .set reorder + j ra // return + + .end HalpSweepIcacheOrion + + SBTTL("Zero Page") +//++ +// +// VOID +// HalpZeroPageOrion ( +// IN PVOID NewColor, +// IN PVOID OldColor, +// IN ULONG PageFrame +// ) +// +// Routine Description: +// +// This function zeros a page of memory. +// +// The algorithm used to zero a page is as follows: +// +// 1. Purge (hit/invalidate) the page from the instruction cache +// using the old color iff the old color is not the same as +// the new color. +// +// 2. Purge (hit/invalidate) the page from the data cache using +// the old color iff the old color is not the same as the new +// color. +// +// 3. Create (create/dirty/exclusive) the page in the data cache +// using the new color. +// +// 4. Write zeros to the page using the new color. +// +// Arguments: +// +// NewColor (a0) - Supplies the page aligned virtual address of the +// new color of the page that is zeroed. +// +// OldColor (a1) - Supplies the page aligned virtual address of the +// old color of the page that is zeroed. +// +// PageFrame (a2) - Supplies the page frame number of the page that +// is zeroed. +// +// Return Value: +// +// None. +// +//-- + + .struct 0 + .space 3 * 4 // fill +ZpRa: .space 4 // saved return address +ZpFrameLength: // length of stack frame +ZpA0: .space 4 // (a0) +ZpA1: .space 4 // (a1) +ZpA2: .space 4 // (a2) +ZpA3: .space 4 // (a3) + + NESTED_ENTRY(HalpZeroPageOrion, ZpFrameLength, zero) + + subu sp,sp,ZpFrameLength // allocate stack frame + sw ra,ZpRa(sp) // save return address + + PROLOGUE_END + + and a0,a0,COLOR_BITS // isolate new color bits + and a1,a1,COLOR_BITS // isolate old color bits + sw a0,ZpA0(sp) // save new color bits + sw a1,ZpA1(sp) // save old color bits + sw a2,ZpA2(sp) // save page frame + +// +// If the old page color is not equal to the new page color, then change +// the color of the page. +// + + beq a0,a1,10f // if eq, colors match + jal KeChangeColorPage // chagne page color + +// +// Create dirty exclusive cache blocks and zero the data. +// + +10: lw a3,ZpA0(sp) // get new color bits + lw a1,ZpA2(sp) // get page frame number + + .set noreorder + .set noat + lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache polciy + li t0,FLUSH_BASE // get base flush address + or t0,t0,a3 // compute new color virtual address + sll t1,a1,ENTRYLO_PFN // shift page frame into position + or t1,t1,PROTECTION_BITS // merge protection bits + or t1,t1,v0 // merge cache policy + and a3,a3,0x1000 // isolate TB entry index + beql zero,a3,20f // if eq, first entry + move t2,zero // set second page table entry + move t2,t1 // set second page table entry + move t1,zero // set first page table entry +20: mfc0 t3,wired // get TB entry index + lw t4,KiPcr + PcFirstLevelDcacheFillSize(zero) // get 1st fill size + lw v0,KiPcr + PcSecondLevelDcacheFillSize(zero) // get 2nd fill size + .set at + .set reorder + + DISABLE_INTERRUPTS(t5) // disable interrupts + + .set noreorder + .set noat + mfc0 t6,entryhi // get current PID and VPN2 + srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address + sll t7,t7,ENTRYHI_VPN2 // + and t6,t6,0xff << ENTRYHI_PID // isolate current PID + or t7,t7,t6 // merge PID with VPN2 of virtual address + mtc0 t7,entryhi // set VPN2 and PID for probe + mtc0 t1,entrylo0 // set first PTE value + mtc0 t2,entrylo1 // set second PTE value + mtc0 t3,index // set TB index value + nop // fill + tlbwi // write TB entry - 3 cycle hazzard + addu t9,t0,PAGE_SIZE // compute ending address of block + dmtc1 zero,f0 // set write pattern + and t8,t4,0x10 // test if 16-byte cache block + +// +// Zero page in primary and secondary data caches. +// + +50: sdc1 f0,0(t0) // zero 64-byte block + sdc1 f0,8(t0) // + sdc1 f0,16(t0) // + sdc1 f0,24(t0) // + sdc1 f0,32(t0) // + sdc1 f0,40(t0) // + sdc1 f0,48(t0) // + addu t0,t0,64 // advance to next 64-byte block + bne t0,t9,50b // if ne, more to zero + sdc1 f0,-8(t0) // + + .set at + .set reorder + + ENABLE_INTERRUPTS(t5) // enable interrupts + + lw ra,ZpRa(sp) // get return address + addu sp,sp,ZpFrameLength // deallocate stack frame + j ra // return + + .end HalpZeroPageOrion + + diff --git a/private/ntos/nthals/halsnip/mips/r4intdsp.c b/private/ntos/nthals/halsnip/mips/r4intdsp.c new file mode 100644 index 000000000..08f79fb39 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/r4intdsp.c @@ -0,0 +1,1307 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/r4intdsp.c,v 1.9 1996/02/23 17:55:12 pierre Exp $") + +/*++ + +Copyright (c) 1993 - 1994 Siemens Nixdorf Informationssysteme AG + +Module Name: + + r4intdsp.c + +Abstract: + + This module contains the HalpXxx routines which are important to + handle the Interrupts on the SNI machines. + +Environment: + + Kernel mode + +--*/ + +#include "halp.h" +#include "SNIregs.h" +#include "mpagent.h" +#include "eisa.h" +#include "pci.h" + +// +// Define the context structure for use by the interrupt routine. +// + +typedef BOOLEAN (*PSECONDARY_DISPATCH)( + PVOID InterruptRoutine + ); + +typedef BOOLEAN (*PINT0_DISPATCH)( + PKINTERRUPT Interupt, + PVOID ServiceContext + ); + +extern VOID HalpSendIpi(IN ULONG pcpumask, IN ULONG msg_data); + +KINTERRUPT HalpInt0Interrupt; // Interrupt Object for SC machines (centralised interrupt) +KINTERRUPT HalpInt3Interrupt; // Interrupt Object for IT3 tower multipro + +ULONG HalpTargetRetryCnt=0; // Counter for pci error ( initiator receives target retry) +ULONG HalpSingleEccCounter = 0; // Single Ecc Error Counter (for RM200/RM300) + +extern VOID +HalpReadPCIConfig ( + IN ULONG BusNumber, + IN PCI_SLOT_NUMBER Slot, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +extern VOID +HalpWritePCIConfig ( + IN ULONG BusNumber, + IN PCI_SLOT_NUMBER Slot, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +extern BOOLEAN +HalpPciEisaDispatch( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ) ; + +extern BOOLEAN +HalpPciEisaSBDispatch( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ) ; + +extern BOOLEAN HalpESC_SB; + +BOOLEAN +HalpCreateIntPciStructures ( + VOID + ) + +/*++ + +Routine Description: + + This routine initializes the structures necessary for Int0-handling + and connects the intermediate interrupt dispatcher. + Also the structures necessary for PCI tower Int3 (MAUI interrupt) + +Arguments: + + None. + +Return Value: + + If the second level interrupt dispatcher are connected, then a value of + TRUE is returned. Otherwise, a value of FALSE is returned. + +--*/ + +{ + + PVOID InterruptSourceRegister; + PINT0_DISPATCH (DispatchRoutine); + PKSPIN_LOCK pSpinLock; + + switch (HalpMainBoard) { + case M8150 : InterruptSourceRegister = (PVOID)PCI_TOWER_INTERRUPT_SOURCE_REGISTER; + DispatchRoutine = HalpPciTowerInt0Dispatch; + pSpinLock = (PKSPIN_LOCK)NULL; + break; + + default: InterruptSourceRegister = (PVOID)PCI_INTERRUPT_SOURCE_REGISTER; + DispatchRoutine = HalpPciInt0Dispatch; + pSpinLock = &HalpInterruptLock; + } + + KeInitializeInterrupt( &HalpInt0Interrupt, + DispatchRoutine, + InterruptSourceRegister, + (PKSPIN_LOCK)pSpinLock, + INT0_LEVEL, + INT0_LEVEL, //INT0_LEVEL, + INT0_LEVEL, //Synchr. Level + LevelSensitive, + FALSE, // only one Intobject ispossible for int0 + 0, // processor number + FALSE // floating point registers + // and pipe line are not + // saved before calling + // the service routine + ); + + + if (!KeConnectInterrupt( &HalpInt0Interrupt )) { + + // + // this is the central Interrupt for the SNI SecondLevel Cache Machines + // + + HalDisplayString("Failed to connect Int0!\n"); + return(FALSE); + } + + + + return (TRUE); +} + + + +BOOLEAN +HalpCreateIntPciMAUIStructures ( + CCHAR Number + ) + +/*++ + +Routine Description: + + This routine initializes the structures necessary + for PCI tower Int3 (MAUI interrupt) + +Arguments: + + None. + +Return Value: + + If the second level interrupt dispatcher are connected, then a value of + TRUE is returned. Otherwise, a value of FALSE is returned. + +--*/ + +{ + +PVOID InterruptSourceRegister; + + InterruptSourceRegister = (PVOID)PCI_TOWER_INTERRUPT_SOURCE_REGISTER; + + KeInitializeInterrupt( &HalpInt3Interrupt, + HalpPciTowerInt3Dispatch, + InterruptSourceRegister, + (PKSPIN_LOCK)&HalpInterruptLock, + INT6_LEVEL, + INT6_LEVEL, //INT6_LEVEL, + INT6_LEVEL, //Synchr. Level + LevelSensitive, + FALSE, // only one Intobject ispossible for int0 + Number, // processor number + FALSE // floating point registers + // and pipe line are not + // saved before calling + // the service routine + ); + + + if (!KeConnectInterrupt( &HalpInt3Interrupt )) { + + // + // this is the central Interrupt for the SNI SecondLevel Cache Machines + // + + HalDisplayString("Failed to connect Int3!\n"); + return(FALSE); + } + } + + + +BOOLEAN +HalpPciInt0Dispatch ( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ) +/*++ +Routine Description: + + This routine handles the central INT0 Interrupt on an SNI PCI Desktop or Minitower + To decide which interrupt, read the Interrupt Source Register + + We have to manage priorities by software. + +Arguments: + + Interrupt - Supplies a pointer to the interrupt object. + + ServiceContext - Supplies a pointer to the Interrupt + Source register. + + +Return Value: + + A BOOLEAN value, TRUE if the interrupt is OK, + otherwise FALSE for unknown interrupts + +--*/ + +{ + UCHAR IntSource; + UCHAR MaStatus; + ULONG Itpend; + + BOOLEAN SCSIresult, NETresult, result; + + if (HalpCheckSpuriousInt(0x400)) return(FALSE); + + + IntSource = READ_REGISTER_UCHAR(ServiceContext); + + IntSource ^= PCI_INTERRUPT_MASK; // XOR the low active bits with 1 gives 1 + // and XOR the high active with 0 gives 1 + + if ( IntSource & PCI_EISA_MASK) { // EISA Interrupt + + if (HalpESC_SB) + result = HalpPciEisaSBDispatch( NULL, // InterruptObject (unused) + (PVOID)EISA_CONTROL_PHYSICAL_BASE // ServiceContext + ); + else + result = HalpPciEisaDispatch( NULL, // InterruptObject (unused) + (PVOID)EISA_CONTROL_PHYSICAL_BASE // ServiceContext + ); + + HalpCheckSpuriousInt(0x00); + return(result); + } + + // + // look for SCSI Interrupts + // + + if ( IntSource & PCI_SCSI_MASK){ + SCSIresult = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[SCSI_VECTOR])( + PCR->InterruptRoutine[SCSI_VECTOR] + ); +#if DBG + if(!SCSIresult) DebugPrint(("Got an invalid SCSI interrupt !\n")); +#endif + HalpCheckSpuriousInt(0x00); + return(SCSIresult); + + } + + // + // PCI interrupts + // + + if ( IntSource & PCI_INTA_MASK){ + int i; + for (i=INTA_VECTOR;i<HalpIntAMax;++i) + ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[i])( + PCR->InterruptRoutine[i] + ); + HalpCheckSpuriousInt(0x00); + return(TRUE); + } + + if ( IntSource & PCI_INTB_MASK){ + int i; + for (i=INTB_VECTOR;i<HalpIntBMax;++i) + ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[i])( + PCR->InterruptRoutine[i] + ); + HalpCheckSpuriousInt(0x00); + return(TRUE); + } + + if ( IntSource & PCI_INTC_MASK){ + int i; + for (i=INTC_VECTOR;i<HalpIntCMax;++i) + ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[i])( + PCR->InterruptRoutine[i] + ); + HalpCheckSpuriousInt(0x00); + return(TRUE); + } + + if ( IntSource & PCI_INTD_MASK){ + int i; + for (i=INTD_VECTOR;i<HalpIntDMax;++i) + ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[i])( + PCR->InterruptRoutine[i] + ); + HalpCheckSpuriousInt(0x00); + return(TRUE); + } + + // + // look for an Ethernet Interrupt + // + + if ( IntSource & PCI_NET_MASK){ + NETresult = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[NET_LEVEL])( + PCR->InterruptRoutine[NET_LEVEL] + ); + HalpCheckSpuriousInt(0x00); + return(NETresult); + } + + // + // Other interrupts => look in MSR register + // + + if ( IntSource & PCI_INT2_MASK) { + + MaStatus = READ_REGISTER_UCHAR(PCI_MSR_ADDR); + if (HalpMainBoard == DesktopPCI) { + MaStatus ^= PCI_MSR_MASK_D; + } else { + MaStatus ^= PCI_MSR_MASK_MT; + } + + // + // look for an ASIC interrupt + // + + if ( MaStatus & PCI_MSR_ASIC_MASK){ + + Itpend = READ_REGISTER_ULONG(PCI_ITPEND_REGISTER); + + if ( Itpend & (PCI_ASIC_ECCERROR | PCI_ASIC_TRPERROR)) { + + ULONG ErrAddr, AsicErrAddr, Syndrome, ErrStatus, irqsel; + + AsicErrAddr = ErrAddr = READ_REGISTER_ULONG(PCI_ERRADDR_REGISTER); + Syndrome = READ_REGISTER_ULONG(PCI_SYNDROME_REGISTER); + Syndrome &= 0xff; // only 8 lower bits are significant + ErrStatus = READ_REGISTER_ULONG(PCI_ERRSTATUS_REGISTER); + + if (ErrStatus & PCI_MEMSTAT_PARERR) { + // Parity error (PCI_ASIC <-> CPU) + irqsel = READ_REGISTER_ULONG(PCI_IRQSEL_REGISTER); + WRITE_REGISTER_ULONG( PCI_IRQSEL_REGISTER , + (irqsel & 0x70000)); // PARERR it not routed + ErrAddr = HalpFindEccAddr(AsicErrAddr,(PVOID)PCI_ERRSTATUS_REGISTER,(PVOID)PCI_MEMSTAT_PARERR); + + if (ErrAddr == -1) ErrAddr = AsicErrAddr; + +#if DBG + DebugPrint(("pci_memory_error : errstatus=0x%x Add error=0x%x syndrome=0x%x \n", + ErrStatus,ErrAddr,Syndrome)); + DbgBreakPoint(); +#else + HalpDisableInterrupts(); // for the MATROX boards... + HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode + HalDisplayString("\n"); + HalpClearVGADisplay(); + HalpBugCheckNumber = 1; + HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "PARITY ERROR\n" + HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,ErrAddr,HalpComputeNum((UCHAR *)ErrAddr),Syndrome); +#endif + } + + if (ErrStatus & PCI_MEMSTAT_ECCERR) { + // ECC error (PCI_ASIC <-> Memory access) + AsicErrAddr &= 0xfffffff8; + irqsel = READ_REGISTER_ULONG(PCI_IRQSEL_REGISTER); + WRITE_REGISTER_ULONG( PCI_IRQSEL_REGISTER , + (irqsel & 0xe000)); // ECC it not routed + ErrAddr = HalpFindEccAddr(AsicErrAddr,(PVOID)PCI_ERRSTATUS_REGISTER,(PVOID)PCI_MEMSTAT_ECCERR); + + if (ErrAddr == -1) ErrAddr = AsicErrAddr; + + if (ErrStatus & PCI_MEMSTAT_ECCSINGLE) { +// HalSweepDcacheRange(0x80000000,2*(PCR->FirstLevelDcacheSize)); // to avoid data_coherency_exception +// HalSweepIcacheRange(0x80000000,2*(PCR->FirstLevelIcacheSize)); // to avoid data_coherency_exception + if (HalpProcessorId == MPAGENT) + HalpMultiPciEccCorrector(ErrAddr,ErrAddr >> PAGE_SHIFT,4); + else + HalpPciEccCorrector(ErrAddr,ErrAddr >> PAGE_SHIFT,4); +// HalSweepDcacheRange(0x80000000,2*(PCR->FirstLevelDcacheSize)); // to avoid data_coherency_exception +// HalSweepIcacheRange(0x80000000,2*(PCR->FirstLevelIcacheSize)); // to avoid data_coherency_exception + + WRITE_REGISTER_ULONG( PCI_IRQSEL_REGISTER, irqsel); // restore routage ECC + + if (ErrAddr == READ_REGISTER_ULONG(PCI_ERRADDR_REGISTER)) { + Syndrome = READ_REGISTER_ULONG(PCI_SYNDROME_REGISTER); + ErrStatus = READ_REGISTER_ULONG(PCI_ERRSTATUS_REGISTER); + KeStallExecutionProcessor(100); + } + + // We use SNI_PRIVATE_VECTOR to transmit parameters to the RM300 equivalent DCU' driver + + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->DCU_reserved=0; + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->DCU_reserved_bis=FLAG_ECC_ERROR; + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EccErrorSimmNum=HalpComputeNum((UCHAR *)ErrAddr); + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EccErrorAddress=ErrAddr; + + // Call the 'RM300 equivalent DCU' driver to log the ECC error in event viewer + + result = (((PSECONDARY_DISPATCH) PCR->InterruptRoutine[DCU_VECTOR])( + PCR->InterruptRoutine[DCU_VECTOR] + )); + ++HalpSingleEccCounter; + if (HalpSingleEccCounter > 0xffff) { +#if DBG + HalpSingleEccCounter = 0; + DebugPrint(("Memory Read Error Counter Overflow\n")); + DbgBreakPoint(); +#else + HalpDisableInterrupts(); // for the MATROX boards... + HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode + HalDisplayString("\n"); + HalpClearVGADisplay(); + HalpBugCheckNumber = 2; + HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "ECC SINGLE ERROR COUNTER OVERFLOW\n" + HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,ErrAddr,HalpComputeNum((UCHAR *)ErrAddr),Syndrome); +#endif + } + + } else { + +#if DBG + // UNIX => PANIC + DebugPrint(("pci_ecc_error : errstatus=0x%x Add error=0x%x syndrome=0x%x \n", + ErrStatus,ErrAddr,Syndrome)); + DbgBreakPoint(); +#else + HalpDisableInterrupts(); // for the MATROX boards... + HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode + HalDisplayString("\n"); + HalpClearVGADisplay(); + HalpBugCheckNumber = 3; + HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "UNCORRECTABLE ECC ERROR\n" + HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,ErrAddr,HalpComputeNum((UCHAR *)ErrAddr),Syndrome); +#endif + } + + } + + } + + if ( Itpend & PCI_ASIC_IOTIMEOUT ) { + + ULONG ioadtimeout2, iomemconf; + + ioadtimeout2 = READ_REGISTER_ULONG(PCI_IOADTIMEOUT2_REGISTER); + iomemconf = READ_REGISTER_ULONG(PCI_IOMEMCONF_REGISTER); + WRITE_REGISTER_ULONG( PCI_IOMEMCONF_REGISTER , + (iomemconf & (~PCI_IOMEMCONF_ENIOTMOUT))); + // reenable timeout + WRITE_REGISTER_ULONG( PCI_IOMEMCONF_REGISTER , iomemconf ); +#if DBG + DebugPrint(("pci_timeout_error : adresse=0x%x \n",ioadtimeout2)); + DbgBreakPoint(); +#else + HalpDisableInterrupts(); // for the MATROX boards... + HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode + HalDisplayString("\n"); + HalpClearVGADisplay(); + HalpBugCheckNumber = 4; + HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "PCI TIMEOUT ERROR\n" + HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,ioadtimeout2,0,0); +#endif + } + } + + // + // Pb NMI because of cirrus chip which generates a parity which is understood by the ASIC + // like an error and transmit as an NMI EISA. + // + + if (MaStatus & PCI_MSR_NMI) { + + UCHAR DataByte; + + DataByte = READ_REGISTER_UCHAR(&((PEISA_CONTROL) HalpOnboardControlBase)->NmiStatus); + + if (((PNMI_STATUS) &DataByte)->ParityNmi == 1) { + + DebugPrint(("Parity error from system memory\n")); + + // reset NMI interrupt + ((PNMI_STATUS) &DataByte)->DisableEisaParity = 1; + WRITE_REGISTER_UCHAR(&((PEISA_CONTROL) HalpOnboardControlBase)->NmiStatus,DataByte); + + ((PNMI_STATUS) &DataByte)->DisableEisaParity = 0; + WRITE_REGISTER_UCHAR(&((PEISA_CONTROL) HalpOnboardControlBase)->NmiStatus,DataByte); + } + + DataByte = READ_REGISTER_UCHAR(&((PEISA_CONTROL) HalpOnboardControlBase)->ExtendedNmiResetControl); + + if (((PNMI_EXTENDED_CONTROL) &DataByte)->PendingBusMasterTimeout == 1) { + + DebugPrint(("EISA Bus Master timeout\n")); + + // reset NMI interrupt + + ((PNMI_EXTENDED_CONTROL) &DataByte)->EnableBusMasterTimeout = 0; + WRITE_REGISTER_UCHAR(&((PEISA_CONTROL) HalpOnboardControlBase)->ExtendedNmiResetControl,DataByte); + + ((PNMI_EXTENDED_CONTROL) &DataByte)->EnableBusMasterTimeout = 1; + WRITE_REGISTER_UCHAR(&((PEISA_CONTROL) HalpOnboardControlBase)->ExtendedNmiResetControl,DataByte); + + } + + } + + // + // look for an PushButton Interrupt and simply dismiss it + // + + if ( MaStatus & PCI_MSR_PB_MASK){ + DebugPrint(("Interrupt - PushButton\n")); + WRITE_REGISTER_ULONG( PCI_CSRSTBP_ADDR ,0x0); // reset debug intr +#if DBG + DbgBreakPoint(); +#endif + KeStallExecutionProcessor(500000); // sleep 0.5 sec + } + + // + // look for an OverTemperature Interrupt and simply dismiss it + // + + if ( MaStatus & PCI_MSR_TEMP_MASK){ + + DebugPrint(("Interrupt - Temperature\n")); + + // we use SNI_PRIVATE_VECTOR->DCU_reserved to transmit the interrupt sources to + // the 'RM300 equivalent DCU' driver + + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->DCU_reserved= MaStatus; + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->DCU_reserved_bis = 0; //no ECC error + result = (((PSECONDARY_DISPATCH) PCR->InterruptRoutine[DCU_VECTOR])( + PCR->InterruptRoutine[DCU_VECTOR] + )); + + // if DCU driver not installed, Reset interrupt + auto-rearm + + READ_REGISTER_ULONG( PCI_CLR_TMP_ADDR); + + } + + // + // look for an power off + // + + if ( MaStatus & PCI_MSR_POFF_MASK){ + + // we use SNI_PRIVATE_VECTOR->DCU_reserved to transmit the interrupt sources to + // the 'RM300 equivalent DCU' driver + + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->DCU_reserved= MaStatus; + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->DCU_reserved_bis = 0; //No ECC error + result = (((PSECONDARY_DISPATCH) PCR->InterruptRoutine[DCU_VECTOR])( + PCR->InterruptRoutine[DCU_VECTOR] + )); + + // if DCU driver not installed, Reset interrupt + auto-rearm + + WRITE_REGISTER_ULONG( PCI_CLRPOFF_ADDR,0); + } + + // + // look for an power management + // + + if ( MaStatus & PCI_MSR_PMGNT_MASK){ + + // we use SNI_PRIVATE_VECTOR->DCU_reserved to transmit the interrupt sources to + // the 'RM300 equivalent DCU' driver + + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->DCU_reserved= MaStatus; + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->DCU_reserved_bis = 0; //No ECC error + result = (((PSECONDARY_DISPATCH) PCR->InterruptRoutine[DCU_VECTOR])( + PCR->InterruptRoutine[DCU_VECTOR] + )); + + // if DCU driver not installed, Reset interrupt + auto-rearm + + WRITE_REGISTER_ULONG( PCI_PWDN_ADDR,0); // power down + } + } + + HalpCheckSpuriousInt(0x00); + return (TRUE); // perhaps one of the interrupts was pending :-) +} + + +BOOLEAN +HalpPciTowerInt0Dispatch ( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ) +/*++ +Routine Description: + + This routine handles the central INT0 Interrupt on an SNI PCI tower + To decide which interrupt, read the Interrupt Source Register + + We have to manage priorities by software. + +Arguments: + + Interrupt - Supplies a pointer to the interrupt object. + + ServiceContext - Supplies a pointer to the Interrupt + Source register. + + +Return Value: + + A BOOLEAN value, TRUE if the interrupt is OK, + otherwise FALSE for unknown interrupts + +--*/ + +{ + ULONG IntSource; + BOOLEAN SCSIresult, result; + + if (HalpCheckSpuriousInt(0x400)) return(FALSE); + + IntSource = READ_REGISTER_ULONG(ServiceContext); + + + + if ( IntSource & PCI_TOWER_EISA_MASK) { // EISA Interrupt + if (HalpESC_SB) + result = HalpPciEisaSBDispatch( NULL, // InterruptObject (unused) + (PVOID)EISA_CONTROL_PHYSICAL_BASE // ServiceContext + ); + else + result = HalpPciEisaDispatch( NULL, // InterruptObject (unused) + (PVOID)EISA_CONTROL_PHYSICAL_BASE // ServiceContext + ); + HalpCheckSpuriousInt(0x00); + return(result); + } + + // + // look for SCSI Interrupts + // + + if ( IntSource & PCI_TOWER_SCSI1_MASK){ + + + + SCSIresult = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[SCSI1_VECTOR])( + PCR->InterruptRoutine[SCSI1_VECTOR] + ); +#if DBG + if(!SCSIresult) DebugPrint(("Got an invalid SCSI 1 interrupt !\n")); +#endif + HalpCheckSpuriousInt(0x00); + return(SCSIresult); + + } + if ( IntSource & PCI_TOWER_SCSI2_MASK){ + SCSIresult = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[SCSI2_VECTOR])( + PCR->InterruptRoutine[SCSI2_VECTOR] + ); +#if DBG + if(!SCSIresult) DebugPrint(("Got an invalid SCSI 2 interrupt !\n")); +#endif + HalpCheckSpuriousInt(0x00); + return(SCSIresult); + + } + // + // PCI interrupts + // + + if ( IntSource & PCI_TOWER_INTA_MASK){ + int i; + for (i=INTA_VECTOR;i<HalpIntAMax;++i) + ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[i])( + PCR->InterruptRoutine[i] + ); + HalpCheckSpuriousInt(0x00); + return(TRUE); + } + + if ( IntSource & PCI_TOWER_INTB_MASK){ + int i; + for (i=INTB_VECTOR;i<HalpIntBMax;++i) + ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[i])( + PCR->InterruptRoutine[i] + ); + HalpCheckSpuriousInt(0x00); + return(TRUE); + } + + if ( IntSource & PCI_TOWER_INTC_MASK){ + int i; + for (i=INTC_VECTOR;i<HalpIntCMax;++i) + ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[i])( + PCR->InterruptRoutine[i] + ); + HalpCheckSpuriousInt(0x00); + return(TRUE); + } + + if ( IntSource & PCI_TOWER_INTD_MASK){ + int i; + for (i=INTD_VECTOR;i<HalpIntDMax;++i) + ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[i])( + PCR->InterruptRoutine[i] + ); + HalpCheckSpuriousInt(0x00); + return(TRUE); + } + + + + + + HalpCheckSpuriousInt(0x00); + return (TRUE); // perhaps one of the interrupts was pending :-) +} + + + +BOOLEAN +HalpPciTowerInt3Dispatch ( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ) +/*++ +Routine Description: + + This routine handles the MAUI-INT4 Interrupt on an SNI PCI tower : + - DCU interrupt (extra_timer,...) + - MPBus error + - Memory error + - PCI error + + To decide which interrupt, read the Interrupt Source Register + + We have to manage priorities by software. + +Arguments: + + Interrupt - Supplies a pointer to the interrupt object. + + ServiceContext - Supplies a pointer to the Interrupt + Source register. + + +Return Value: + + A BOOLEAN value, TRUE if the interrupt is OK, + otherwise FALSE for unknown interrupts + +--*/ + +{ + ULONG IntSource; + ULONG mem_addr,status; + ULONG status0,status1; + BOOLEAN result; + + + if (HalpCheckSpuriousInt(0x2000)) return(FALSE); + + + IntSource = READ_REGISTER_ULONG(ServiceContext); + + + // + // look if a DCU_INDICATE interrupt occured + // + // + + if (IntSource & PCI_TOWER_D_INDICATE_MASK){ + + + status = READ_REGISTER_ULONG(PCI_TOWER_INDICATE); + + // + // look if extra timer interrupt + // + + if (status & PCI_TOWER_DI_EXTRA_TIMER){ + + HalpClockInterruptPciTower(); + return(TRUE); + } + + DebugPrint(("DCU_INDICATE interrupt\n")); + // + // look for an PushButton Interrupt and simply dismiss it + // + + + if ( status & PCI_TOWER_DI_PB_MASK){ + + DebugPrint(("Interrupt - PushButton\n")); + +#if DBG + DbgBreakPoint(); +#endif + KeStallExecutionProcessor(500000); // sleep 0.5 sec + + return(TRUE); + } + + + //The reading of DCU_INDICATE register clears the interrupt sources + // --> we use SNI_PRIVATE_VECTOR->DCU_reserved to transmit the interrupt sources to + // the DCU driver + result = TRUE; + + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->DCU_reserved= status; + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->DCU_reserved_bis = 0; //No ECC error + result = (((PSECONDARY_DISPATCH) PCR->InterruptRoutine[DCU_VECTOR])( + PCR->InterruptRoutine[DCU_VECTOR] + )); + + // if DCU driver not installed, reset EISA_NMI interrupt if necessary + + if (status & PCI_TOWER_DI_EISA_NMI) + { + UCHAR DataByte; + + DataByte = READ_REGISTER_UCHAR(&((PEISA_CONTROL) HalpOnboardControlBase)->NmiStatus); + + + if (((PNMI_STATUS) &DataByte)->ParityNmi == 1) + { + DebugPrint(("Parity error from system memory\n")); + + //reset NMI interrupt // + + ((PNMI_STATUS) &DataByte)->DisableEisaParity = 1; + WRITE_REGISTER_UCHAR(&((PEISA_CONTROL) HalpOnboardControlBase)->NmiStatus,DataByte); + + ((PNMI_STATUS) &DataByte)->DisableEisaParity = 0; + WRITE_REGISTER_UCHAR(&((PEISA_CONTROL) HalpOnboardControlBase)->NmiStatus,DataByte); + } + + + DataByte = READ_REGISTER_UCHAR(&((PEISA_CONTROL) HalpOnboardControlBase)->ExtendedNmiResetControl); + + if (((PNMI_EXTENDED_CONTROL) &DataByte)->PendingBusMasterTimeout == 1) + { + DebugPrint(("EISA Bus Master timeout\n")); + + //reset NMI interrupt // + + ((PNMI_EXTENDED_CONTROL) &DataByte)->EnableBusMasterTimeout = 0; + WRITE_REGISTER_UCHAR(&((PEISA_CONTROL) HalpOnboardControlBase)->ExtendedNmiResetControl,DataByte); + + ((PNMI_EXTENDED_CONTROL) &DataByte)->EnableBusMasterTimeout = 1; + WRITE_REGISTER_UCHAR(&((PEISA_CONTROL) HalpOnboardControlBase)->ExtendedNmiResetControl,DataByte); + } + } + + return (result); + } + + // + // look if a DCU_ERROR interrupt occured + // + // + + if (IntSource & PCI_TOWER_D_ERROR_MASK){ + + status = 0; + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->DCU_reserved= 0; + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->DCU_reserved_bis = 0; //No ECC error + result =(((PSECONDARY_DISPATCH) PCR->InterruptRoutine[DCU_VECTOR])( + PCR->InterruptRoutine[DCU_VECTOR] + )); + // read DCU_ERROR register to clear interrupt source if DCU driver not installed + READ_REGISTER_ULONG(PCI_TOWER_DCU_ERROR); + return (result); + } + + + + // + // look if MP_BUS error + // + + + if (IntSource & PCI_TOWER_MP_BUS_MASK){ + + + status = READ_REGISTER_ULONG(PCI_TOWER_MP_BUS_ERROR_STATUS); + mem_addr = READ_REGISTER_ULONG(PCI_TOWER_MP_BUS_ERROR_ADDR); + + // Clear MP_Bus interrupt + + WRITE_REGISTER_ULONG (ServiceContext,IntSource); + + + if (IntSource & PCI_TOWER_C_PARITY_MASK){ + +#if DBG + DebugPrint(("MP_Bus Parity Error : MPBusErrorStatus = 0x%x MPBusErrorAddress = 0x%x \n", + status,mem_addr)); + //DbgBreakPoint(); +#else + HalpDisableInterrupts(); // for the MATROX boards... + HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode + HalDisplayString("\n"); + HalpClearVGADisplay(); + HalpBugCheckNumber = 5; + HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "MP_BUS PARITY ERROR\n" + HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,status,mem_addr,0); +#endif + } + + if (IntSource & PCI_TOWER_C_REGSIZE){ +#if DBG + DebugPrint(("MP_Bus Register Size Error : MPBusErrorStatus = 0x%x \n", + status)); + DbgBreakPoint(); + +#else + HalpDisableInterrupts(); // for the MATROX boards... + HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode + HalDisplayString("\n"); + HalpClearVGADisplay(); + HalpBugCheckNumber = 6; + HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "MP_BUS REGISTER SIZE ERROR\n" + HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,status,0,0); +#endif + } + } + + // + // look if Memory error + // + if (IntSource & PCI_TOWER_M_ECC_MASK){ + + + mem_addr = READ_REGISTER_ULONG(PCI_TOWER_MEM_ERROR_ADDR)& MEM_ADDR_MASK; + + // correct ECC error + HalpMultiPciEccCorrector(mem_addr ,mem_addr >> PAGE_SHIFT,4); + + IntSource = READ_REGISTER_ULONG(PCI_TOWER_GEN_INTERRUPT); + if (IntSource & PCI_TOWER_M_ECC_MASK){ + + mem_addr = READ_REGISTER_ULONG(PCI_TOWER_MEM_ERROR_ADDR)& MEM_ADDR_MASK; + KeStallExecutionProcessor(100); + } + // We use SNI_PRIVATE_VECTOR to transmit parameters to DCU driver + + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->DCU_reserved=0; + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->DCU_reserved_bis=FLAG_ECC_ERROR; + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EccErrorSimmNum=HalpComputeNum((UCHAR *)mem_addr); + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EccErrorAddress= mem_addr ; + + // Call the 'DCU' driver to log the ECC error in event viewer + + result = (((PSECONDARY_DISPATCH) PCR->InterruptRoutine[DCU_VECTOR])( + PCR->InterruptRoutine[DCU_VECTOR] + )); + + + } + + if (IntSource & PCI_TOWER_M_ADDR_MASK){ + + mem_addr = READ_REGISTER_ULONG(PCI_TOWER_MEM_ERROR_ADDR); +#if DBG + DebugPrint(("Memory Address Error : MemErrorAddr = 0x%x \n",mem_addr)); + DbgBreakPoint(); +#else + HalpDisableInterrupts(); // for the MATROX boards... + HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode + HalDisplayString("\n"); + HalpClearVGADisplay(); + HalpBugCheckNumber = 7; + HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "MEMORY ADDRESS ERROR\n" + HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,mem_addr,0,0); +#endif + } + + if (IntSource & PCI_TOWER_M_SLT_MASK){ + + ULONG MemControl2,MemConf; + + MemControl2 = READ_REGISTER_ULONG(PCI_TOWER_MEM_CONTROL_2); + MemConf = READ_REGISTER_ULONG(PCI_TOWER_MEM_CONFIG); +#if DBG + DebugPrint(("Memory slot Error : MemControl2 = 0x%x, MemConf = 0x%x \n",MemControl2,MemConf)); + DbgBreakPoint(); +#else + HalpDisableInterrupts(); // for the MATROX boards... + HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode + HalDisplayString("\n"); + HalpClearVGADisplay(); + HalpBugCheckNumber = 8; + HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "MEMORY SLOT ERROR\n" + HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,MemControl2,MemConf,0); +#endif + } + + if (IntSource & PCI_TOWER_M_CFG_MASK){ + + ULONG MemControl2,MemConf; + + MemControl2 = READ_REGISTER_ULONG(PCI_TOWER_MEM_CONTROL_2); + MemConf = READ_REGISTER_ULONG(PCI_TOWER_MEM_CONFIG); +#if DBG + DebugPrint(("Memory Config Error : MemControl2 = 0x%x, MemConf = 0x%x \n",MemControl2,MemConf)); + DbgBreakPoint(); +#else + HalpDisableInterrupts(); // for the MATROX boards... + HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode + HalDisplayString("\n"); + HalpClearVGADisplay(); + HalpBugCheckNumber = 9; + HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "MEMORY CONFIG ERROR\n" + HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,MemControl2,MemConf,0); +#endif + } + + + if (IntSource & PCI_TOWER_M_RC_MASK){ + + // reset error counter + WRITE_REGISTER_ULONG (PCI_TOWER_MEM_CONTROL_1, (READ_REGISTER_ULONG(PCI_TOWER_MEM_CONTROL_1) & ERROR_COUNTER_MASK) | ERROR_COUNTER_INITVALUE); + +#if DBG + DebugPrint(("Memory Read Error Counter Overflow\n")); + DbgBreakPoint(); +#else + HalpDisableInterrupts(); // for the MATROX boards... + HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode + HalDisplayString("\n"); + HalpClearVGADisplay(); + HalpBugCheckNumber = 2; + HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "ECC SINGLE ERROR COUNTER OVERFLOW\n" + HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,0,0,0); +#endif + } + + + + // + // look if PCI interrupt + // + if (IntSource & PCI_TOWER_P_ERROR_MASK){ + ULONG PciDataInt,PciData; + + DebugPrint(("PCI interrupt \n")); + + + PciDataInt = PCI_TOWER_INTERRUPT_OFFSET | 0x80000000; + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciDataInt)); + + status = READ_REGISTER_ULONG ((PULONG) HalpPciConfigData); + + + // First Initiator interrupt + + if (status & PI_INITF){ + + PciData = PCI_TOWER_INITIATOR_ADDR_OFFSET | 0x80000000; + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciData)); + + mem_addr = READ_REGISTER_ULONG ((PULONG) HalpPciConfigData); + + // Reset interrupt with write-1-to-clear bit Initiator_Interrupts + status0 = PI_INITF; + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciDataInt)); + WRITE_REGISTER_ULONG ((PULONG) HalpPciConfigData, *((PULONG) &status0)); + + if (status & PI_REC_TARGET_RETRY) + HalpTargetRetryCnt++; + else { + +#if DBG + DebugPrint(("PCI Iniatiator interrupt error : Addr = 0x%x , PCI_interrupt register = 0x%x\n", + mem_addr,status)); + DbgBreakPoint(); +#else + HalpDisableInterrupts(); // for the MATROX boards... + HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode + HalDisplayString("\n"); + HalpClearVGADisplay(); + HalpBugCheckNumber = 10; + HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "PCI INITIATOR INTERRUPT ERROR\n" + HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,status,mem_addr,0); +#endif + } + } + + // First Target interrupt + + if (status & PI_TARGF){ + PciData = PCI_TOWER_TARGET_ADDR_OFFSET | 0x80000000; + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciData)); + + mem_addr = READ_REGISTER_ULONG ((PULONG) HalpPciConfigData); + + // Reset interrupt with write-1-to-clear bit Target_Interrupts + status0 = PI_TARGF; + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciDataInt)); + WRITE_REGISTER_ULONG ((PULONG) HalpPciConfigData, *((PULONG) &status0)); + + +#if DBG + DebugPrint(("PCI Target interrupt error : Addr = 0x%x , PCI_interrupt register = 0x%x\n", + mem_addr,status)); + DbgBreakPoint(); +#else + HalpDisableInterrupts(); // for the MATROX boards... + HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode + HalDisplayString("\n"); + HalpClearVGADisplay(); + HalpBugCheckNumber = 11; + HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "PCI TARGET INTERRUPT ERROR\n" + HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,status,mem_addr,0); +#endif + + } + + // First parity error + + if (status & PI_PARF){ + + // Reset interrupt with write-1-to-clear bit Parity_Interrupts + status0 = PI_PARF; + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciDataInt)); + WRITE_REGISTER_ULONG ((PULONG) HalpPciConfigData, *((PULONG) &status0)); + + PciData = PCI_TOWER_PAR_0_OFFSET | 0x80000000; + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciData)); + + status0 = READ_REGISTER_ULONG ((PULONG) HalpPciConfigData); + + PciData = PCI_TOWER_PAR_1_OFFSET | 0x80000000; + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciData)); + + status1 = READ_REGISTER_ULONG ((PULONG) HalpPciConfigData); + +#if DBG + DebugPrint(("PCI Parity interrupt error : Parity_0 register = 0x%x , Parity_1 register = 0x%x\n", + status0,status1)); + DbgBreakPoint(); +#else + HalpDisableInterrupts(); // for the MATROX boards... + HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode + HalDisplayString("\n"); + HalpClearVGADisplay(); + HalpBugCheckNumber = 12; + HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "PCI PARITY INTERRUPT ERROR\n" + HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,status0,status1,0); +#endif + + } + + + // Multiple Initiator interrupts + + if (status & PI_INITM){ + + PciData = PCI_TOWER_TARGET_ADDR_OFFSET | 0x80000000; + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciData)); + + mem_addr = READ_REGISTER_ULONG ((PULONG) HalpPciConfigData); + // Reset interrupt with write-1-to-clear bit Multiple Initiator_Interrupts + status0 = PI_INITM; + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciDataInt)); + WRITE_REGISTER_ULONG ((PULONG) HalpPciConfigData, *((PULONG) &status0)); + + + + if (!(status & PI_REC_TARGET_RETRY)) { +#if DBG + DebugPrint(("Multiple PCI Iniatiator interrupt : Addr = 0x%x , PCI_interrupt register = 0x%x\n", + mem_addr,status)); + DbgBreakPoint(); +#else + HalpDisableInterrupts(); // for the MATROX boards... + HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode + HalDisplayString("\n"); + HalpClearVGADisplay(); + HalpBugCheckNumber = 13; + HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "MULTIPLE PCI INITIATOR ERROR\n" + HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,status,mem_addr,0); +#endif + } + } + + // Multiple Target interrupts + + if (status & PI_TARGM){ + + PciData = PCI_TOWER_TARGET_ADDR_OFFSET | 0x80000000; + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciData)); + + mem_addr = READ_REGISTER_ULONG ((PULONG) HalpPciConfigData); + + // Reset interrupt with write-1-to-clear bit Multiple Target_interrupts + status0 = PI_TARGM; + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciDataInt)); + WRITE_REGISTER_ULONG ((PULONG) HalpPciConfigData, *((PULONG) &status0)); + + + +#if DBG + DebugPrint(("Multiple PCI Target interrupt : Addr = 0x%x , PCI_interrupt register = 0x%x\n", + mem_addr,status)); + DbgBreakPoint(); +#else + HalpDisableInterrupts(); // for the MATROX boards... + HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode + HalDisplayString("\n"); + HalpClearVGADisplay(); + HalpBugCheckNumber = 14; + HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "MULTIPLE PCI TARGET ERROR\n" + HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,status,mem_addr,0); +#endif + + } + + // Multiple Parity interrupts + + if (status & PI_PARM){ + + // Reset interrupt with write-1-to-clear bit Multiple Parity_Interrupts + status0 = PI_PARM; + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciDataInt)); + WRITE_REGISTER_ULONG ((PULONG) HalpPciConfigData, *((PULONG) &status0)); + + PciData = PCI_TOWER_PAR_0_OFFSET | 0x80000000; + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciData)); + + status0 = READ_REGISTER_ULONG ((PULONG) HalpPciConfigData); + + PciData = PCI_TOWER_PAR_1_OFFSET | 0x80000000; + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciData)); + + status1 = READ_REGISTER_ULONG ((PULONG) HalpPciConfigData); + + +#if DBG + DebugPrint(("Multiple PCI Parity interrupt : Parity_0 register = 0x%x , Parity_1 register = 0x%x\n", + status0,status1)); + DbgBreakPoint(); +#else + HalpDisableInterrupts(); // for the MATROX boards... + HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode + HalDisplayString("\n"); + HalpClearVGADisplay(); + HalpBugCheckNumber = 15; + HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "MULTIPLE PCI PARITY ERROR\n" + HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,status0,status1,0); +#endif + + } + //reenable PCI interrupt + status &= MASK_INT; + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciDataInt)); + WRITE_REGISTER_ULONG ((PULONG) HalpPciConfigData, *((PULONG) &status)); + + } + HalpCheckSpuriousInt(0x00); + return (TRUE); // perhaps one of the interrupts was pending :-) +} + + + + diff --git a/private/ntos/nthals/halsnip/mips/snidef.h b/private/ntos/nthals/halsnip/mips/snidef.h new file mode 100644 index 000000000..8f803cb46 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/snidef.h @@ -0,0 +1,225 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/snidef.h,v 1.5 1995/11/30 11:12:21 sylvie Exp $") +/*+++ + +Copyright (c) 1993-1994 Siemens Nixdorf Informationssysteme AG +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + SNIdef.h + +Abstract: + + This module is the header file that describes hardware addresses + common for all SNI systems. + + + +---*/ + +#ifndef _SNIDEF_ +#define _SNIDEF_ + + +#if DBG +#define DebugPrint(arg) DbgPrint arg +#else +#define DebugPrint(arg) ; +#endif + +#include "snipci.h" + +#define VESA_BUS_PHYSICAL_BASE 0x1d000000 +#define VESA_BUS (VESA_BUS_PHYSICAL_BASE | KSEG1_BASE) +#define VESA_IO_PHYSICAL_BASE 0x1e000000 +#define VESA_IO (VESA_IO_PHYSICAL_BASE | KSEG1_BASE) +#define PROM_PHYSICAL_BASE 0x1fc00000 // physical base of boot PROM +#define EISA_MEMORY_PHYSICAL_BASE 0x10000000 // physical base of EISA memory +#define EISA_CONTROL_PHYSICAL_BASE 0x14000000 // physical base of EISA I/O Space +#define EISA_MEMORY_BASE (EISA_MEMORY_PHYSICAL_BASE | KSEG1_BASE) +#define EISA_IO (EISA_CONTROL_PHYSICAL_BASE | KSEG1_BASE) + +// Cache replace addresse for multi-processor machines +#define MPAGENT_RESERVED 0x17c00000 // MP-Agent operator (VL machines and tower PCI) +#define RM300_RESERVED 0x00c00000 // cache replace (memory) for RM300 PCI + +#define NET_PHYSICAL_BASE 0x18000000 // physical base of ethernet control +#define SCSI_PHYSICAL_BASE 0x19000000 // physical base of SCSI control 1 + +#define FLOPPY_CHANNEL 0x2 // Floppy DMA channel +#define FLOPPY_RELATIVE_BASE 0x3f0 // base of floppy control +#define PARALLEL_RELATIVE_BASE 0x3bc // base of parallel port +#define SERIAL0_RELATIVE_BASE 0x3f8 // base of serial port 0 +#define SERIAL1_RELATIVE_BASE 0x2f8 // base of serial port 1 + +#define FLOPPY_PHYSICAL_BASE 0x140003f0 // base of floppy control +#define PARALLEL_PHYSICAL_BASE 0x140003bc // base of parallel port +#define SERIAL0_PHYSICAL_BASE 0x140003f8 // base of serial port 0 +#define SERIAL1_PHYSICAL_BASE 0x140002f8 // base of serial port 1 + +// +// the UCONF, MachineStatus, LED and MachineConfig Registers in the ASIC +// (identical on all SNI machines) +// + +#define UCONF_PHYSICAL_ADDR 0x1fff0000 // interruptions, interface protocol +#define UCONF_ADDR 0xbfff0000 // interruptions, | KSEG1_BASE +#define IOMEMCONF_PHYSICAL_ADDR 0x1fff0010 // I/O and Memory Config (for disable Timeout int) +#define IOMEMCONF_ADDR 0xbfff0010 // I/O and memconf | KSEG1_BASE + +// +// some debugging information registers in the ASIC +// common on all SNI machines +// + +#define DMACCES_PHYSICAL_ADDR 0x1fff0028 // Counter: # of DMA accesses +#define DMACCES 0xbfff0028 // Counter: # of DMA accesses | KSEG1_BASE +#define DMAHIT_PHYSICAL_ADDR 0x1fff0030 // Counter: # of DMA hits +#define DMAHIT 0xbfff0030 // Counter: # of DMA hits | KSEG1_BASE +#define IOMMU_PHYSICAL_ADDR 0x1fff0018 // Select IO space addressing +#define IOMMU 0xbfff0018 // Select IO space addressing | KSEG1_BASE +#define IOADTIMEOUT1_PHYSICAL_ADDR 0x1fff0020 // Current IO context for the first CPU timeout +#define IOADTIMEOUT1 0xbfff0020 // first CPU timeout | KSEG1_BASE +#define IOADTIMEOUT2_PHYSICAL_ADDR 0x1fff0008 // Current IO context on all CPU timeouts +#define IOADTIMEOUT2 0xbfff0008 // all CPU timeouts | KSEG1_BASE + +// +// Define system time increment value. +// + +#define TIME_INCREMENT (10 * 1000 * 10) // Time increment in 100ns units +#define MAXIMUM_INCREMENT (10 * 1000 * 10) +#define MINIMUM_INCREMENT (1 * 1000 * 10) + +#define EXTRA_TIMER_CLOCK_IN 7159090 // 7.15909 Mhz (hard value) +// #define EXTRA_TIMER_CLOCK_IN 7900000 // adjustement to get fq = 10ms + +#define PRE_COUNT 3 // + +// +// Define basic Interrupt Levels which correspond to Cause register bits. +// + +#define INT0_LEVEL 3 +#define INT3_LEVEL 3 +#define SCSIEISA_LEVEL 4 // SCSI/EISA device int. vector +#define EISA_DEVICE_LEVEL 4 // EISA bus interrupt level ??? +#define DUART_VECTOR 5 // DUART SC 2681 int. vector + +#define INT6_LEVEL 6 +#define EXTRA_CLOCK_LEVEL 5 // extra timer on RM300 + +#define PROFILE_LEVEL 8 // Profiling level via Count/compare Interrupt + +#define CLOCK_LEVEL (ONBOARD_VECTORS + 0) // Timer channel 0 in the PC core + +// +// all others are vectors in the interrupt dispatch table. +// + +#define SCSI_VECTOR 9 // SCSI device interrupt vector +#define SCSI1_VECTOR 9 // SCSI 1 device interrupt vector +#define SCSI2_VECTOR 10 // SCSI 2 device interrupt vector +#define NET_DEFAULT_VECTOR 7 // ethernet device internal vector on R4x00 PC !!! + // configured in the Firmware Tree !!!!! +#define NET_LEVEL 10 // ethernet device int. vector + +#define OUR_IPI_LEVEL 7 // multipro machine +#define NETMULTI_LEVEL 5 // multipro machine : ethernet device int. vector + +#define EIP_VECTOR 15 // EIP Interrupt routine +#define DCU_VECTOR 15 // DCU Interrupt routine + +#define CLOCK2_LEVEL CLOCK_LEVEL // System Clock Level + +#define ONBOARD_VECTORS 16 +#define MAXIMUM_ONBOARD_VECTOR (15 + ONBOARD_VECTORS) // maximum Onboard (PC core) vector + +// +// Define EISA device interrupt vectors. +// they only occur when an Eisa Extension is installed in the Desktop model +// + +#define EISA_VECTORS 32 +#define MAXIMUM_EISA_VECTOR (15 + EISA_VECTORS) // maximum EISA vector + +// +// relative interrupt vectors +// only the interrupt vectors relative to the Isa/EISA bus are defined +// + +#define KEYBOARD_VECTOR 1 // Keyboard device interrupt vector +#define SERIAL1_VECTOR 3 // Serial device 1 interrupt vector +#define SERIAL0_VECTOR 4 // Serial device 0 interrupt vector +#define FLOPPY_VECTOR 6 // Floppy device interrupt vector +#define PARALLEL_VECTOR 7 // Parallel device interrupt vector +#define MOUSE_VECTOR 12 // PS/2 Mouse device interrupt vector + + +// PCI interrupts + +#define INTA_VECTOR 50 // PCI INTA first interrupt number +#define INTB_VECTOR 100 // PCI INTB first interrupt number +#define INTC_VECTOR 150 // PCI INTC first interrupt number +#define INTD_VECTOR 200 // PCI INTD first interrupt number + +#define MACHINE_TYPE_ISA 0 +#define MACHINE_TYPE_EISA 1 + + +// +// The MAXIMUM_MAP_BUFFER_SIZE defines the maximum map buffers which the system +// will allocate for devices which require phyically contigous buffers. +// + +#define MAXIMUM_MAP_BUFFER_SIZE 0xc0000 // 768KB for today + +// +// Define the initial buffer allocation size for a map buffers for systems with +// no memory which has a physical address greater than MAXIMUM_PHYSICAL_ADDRESS. +// + +#define INITIAL_MAP_BUFFER_SMALL_SIZE 0x10000 + +// +// Define the initial buffer allocation size for a map buffers for systems with +// no memory which has a physical address greater than MAXIMUM_PHYSICAL_ADDRESS. +// + +#define INITIAL_MAP_BUFFER_LARGE_SIZE 0xc0000 // 256KB as start + +// +// Define the incremental buffer allocation for a map buffers. +// + +#define INCREMENT_MAP_BUFFER_SIZE 0x10000 + +// +// Define the maximum number of map registers that can be requested at one time +// if actual map registers are required for the transfer. +// + +#define MAXIMUM_ISA_MAP_REGISTER 512 + +// +// Define the maximum physical address which can be handled by an Isa card. +// (16MB) +// + +#define MAXIMUM_PHYSICAL_ADDRESS 0x01000000 + +// +// Define the maximum physical address of Main memory on SNI machines +// (256 MB) +// + +#define MAXIMUM_MEMORY_PHYSICAL_ADDRESS 0x10000000 + + +#define COPY_BUFFER 0xFFFFFFFF + +#define NO_SCATTER_GATHER 0x00000001 + + + +#endif /* _SNIDEF_ */ diff --git a/private/ntos/nthals/halsnip/mips/snidisp.c b/private/ntos/nthals/halsnip/mips/snidisp.c new file mode 100644 index 000000000..0e31d4fc0 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/snidisp.c @@ -0,0 +1,1201 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/snidisp.c,v 1.5 1996/03/04 13:24:39 pierre Exp $") +/*++ + +Copyright (c) 1993-94 Siemens Nixdorf Informationssysteme AG +Copyright (c) 1991-93 Microsoft Corporation + +Module Name: + + SNIdisp.c + +Abstract: + + This module implements the HAL display initialization and output routines + for the different SNI machines. + + At the moment we know about the following boards: + WEITEK P9100 PCIBUS (not in the HAL at the moment...) + MATROX STORM PCIBUS ( 80x50 Alpha Mode) + Cirrus 5434 PCI cards ( 80x50 Alpha Mode) + Standard (unknown) VGA on PCI( 80x50 Alpha Mode) + + If we can not identify the board, we don't initialise the display and we call + the vendor printf to display strings. + + At the boot phase all I/O is done via the unmapped uncached Segment (KSEG1) of the + R4000 (HalpEisaControlBase); later with the mapped value of HalpEisaControlBase + Memory is always accessed via unmapped/uncached (KSEG1) area + +Environment: + + Kernel mode + +Revision History: + + Removed HalpInitializeDisplay1, because we do no longer use the P9000 in graphic mode ... + + +NOTE: + + + We did use our own ...MoveMemory() instead of RtlMoveMemory(), + as there is a Hardware bug in our machine and RtlMoveMemory uses + the floating point registers for fast 64 bit move and on our bus + only 32 bit can be found ... :-) + +--*/ + +#include "halp.h" +#include "string.h" +#include "vgadata.h" + +#define MEGA_MOVE_MEMORY(D,S,L) MegaMoveMemory(D,S,L) // orig. RtlMoveMemory() + +// +// supported VGA text modi +// + +typedef enum _TEXT_MODE { + TEXT_80x50, + TEXT_132x50 +} TEXT_MODE; + + +// +// Define forward referenced procedure prototypes. +// + +extern VOID +HalpReadPCIConfig ( + IN ULONG BusNumber, + IN ULONG Slot, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +VOID HalpDisplaySmallCharacter (IN UCHAR Character); +VOID HalpOutputSmallCharacter (IN PUCHAR Font); +VOID HalpInitializeVGADisplay(TEXT_MODE TextMode); +VOID HalpClearVGADisplay (VOID); +VOID HalpDisplayVGAString (PUCHAR String); +VOID HalpPutVGACharacter (UCHAR Character); +VOID HalpNextVGALine (VOID); +VOID HalpScrollVGADisplay (VOID); +VOID DownLoadVGAFont (VOID); +VOID HalpResetS3Chip (VOID); +VOID HalpResetCirrusChip (VOID); +VOID HalpResetP9000 (VOID); +VOID HalpResetMatroxStorm (VOID); +VOID HalpVGASetup (VOID); +VOID HalpDoNoSetup (VOID); + + +typedef +VOID +(*PHALP_CONTROLLER_SETUP) ( + VOID + ); + + +// +// Supported board definitions. +// + +typedef enum _VIDEO_BOARD { + S3_GENERIC, // Standard S3 based Card (miro crystal 8s) + S3_GENERIC_VLB, // Standard S3 based Card (Local Bus) + CIRRUS_GENERIC, // Generic Cirrus VGA (Cirrus CL54xx) + CIRRUS_GENERIC_VLB, // Generic Cirrus VGA (Cirrus CL54xx) (Local Bus) + CIRRUS_ONBOARD, // The Desktop onboard VGA (Cirrus CL5434) + VGA_GENERIC, // generic (unknown) VGA + VGA_GENERIC_VLB, // generic (unknown) VGA on the Vesa Local BUS + MATROX_STORM, + VIDEO_BOARD_UNKNOWN // unknown Display Adapter +} VIDEO_BOARD; + +// +// some supported VGA chips +// + +typedef enum _VIDEO_CHIP { + S3, + CIRRUS, + VGA, // generic (unknown) VGA + VGA_P9000, + VGA_STORM, + VIDEO_CHIP_UNKNOWN +} VIDEO_CHIP; + +typedef struct _VIDEO_BOARD_INFO { + PUCHAR FirmwareString; + PHALP_CONTROLLER_SETUP ControllerSetup; + VIDEO_BOARD VideoBoard; + VIDEO_CHIP VideoChip; +} VIDEO_BOARD_INFO, *PVIDEO_BOARD_INFO; + + +VIDEO_BOARD_INFO KnownVideoBoards[] = { + {"VGA ON PCIBUS", HalpVGASetup , VGA_GENERIC, VGA }, + {"CIRRUS 5434 PCIBUS", HalpVGASetup , CIRRUS_GENERIC, CIRRUS}, + {"MATROX STORM PCIBUS", HalpVGASetup , MATROX_STORM , VGA_STORM } +}; + +LONG numVideoBoards = sizeof (KnownVideoBoards) / sizeof(VIDEO_BOARD_INFO); + +// +// Define static data. +// + +VIDEO_BOARD HalpVideoBoard = VIDEO_BOARD_UNKNOWN; +VIDEO_CHIP HalpVideoChip = VIDEO_CHIP_UNKNOWN; +PHALP_CONTROLLER_SETUP HalpDisplayControllerSetup = HalpDoNoSetup; + +ULONG HalpColumn; +ULONG HalpRow; +ULONG HalpDisplayText; +ULONG HalpDisplayWidth; + +ULONG HalpScrollLength; +ULONG HalpScrollLine; +ULONG HalpBytesPerRow; +PVOID HalpVGAControlBase=( PVOID)( EISA_IO); // Base Address for VGA register access +PUSHORT VideoBuffer = ( PUSHORT)( EISA_MEMORY_BASE + 0xb8000); +PUCHAR FontBuffer = ( PUCHAR )( EISA_MEMORY_BASE + 0xa0000); +BOOLEAN HalpFirstBoot = TRUE; + +ULONG HalpMgaStormBase = 0; +ULONG Halpval40; +ULONG HalpMatroxBus,HalpMatroxSlot; +// +// Declare externally defined data. +// + + +BOOLEAN HalpDisplayOwnedByHal; +PHAL_RESET_DISPLAY_PARAMETERS HalpReturnToVga; + +// +// Put all code for HAL initialization in the INIT section. It will be +// deallocated by memory management when phase 1 initialization is +// completed. +// + +#if defined(ALLOC_PRAGMA) + +#pragma alloc_text(INIT, HalpInitializeDisplay0) +#pragma alloc_text(INIT, HalpInitializeDisplay1) + +#endif + + + +VOID MegaMoveMemory( + OUT PVOID Destination, + IN PVOID Source, + IN ULONG Length + ) +/*++ + + Our private function written to substitute the RtlMoveMemory() + function (64 bit problem). + +--*/ +{ +ULONG lo_index_ul; +PULONG Dst, Src; + + Dst = (PULONG)Destination; + Src = (PULONG)Source; + for (lo_index_ul=0; lo_index_ul < Length/sizeof(ULONG); lo_index_ul++) + *Dst++ = *Src++; +} + +BOOLEAN +HalpInitializeDisplay0 ( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ) + +/*++ + +Routine Description: + + This routine maps the video memory and control registers into the user + part of the idle process address space, initializes the video control + registers, and clears the video screen. + +Arguments: + + LoaderBlock - Supplies a pointer to the loader parameter block. + +Return Value: + + If the initialization is successfully completed, than a value of TRUE + is returned. Otherwise, a value of FALSE is returned. + +--*/ + +{ + PCONFIGURATION_COMPONENT_DATA ConfigurationEntry; + PVIDEO_BOARD_INFO VideoBoard; + LONG Index; + ULONG MatchKey; + + // + // Find the configuration entry for the first display controller. + // + + MatchKey = 0; + ConfigurationEntry = KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot, + ControllerClass, + DisplayController, + &MatchKey); + + if (ConfigurationEntry == NULL) { + return FALSE; + } + + // + // Determine which video controller is present in the system. + // N.B. Be carefull with debug prints during Phase 0, it + // will kill the initial break point request from the debugger ... + // + + + for( Index=0, VideoBoard = KnownVideoBoards; Index < numVideoBoards; Index++, VideoBoard++) { + + if (!strcmp( ConfigurationEntry->ComponentEntry.Identifier, + VideoBoard->FirmwareString + )) { + HalpVideoBoard = VideoBoard->VideoBoard; + HalpVideoChip = VideoBoard->VideoChip; + HalpDisplayControllerSetup = VideoBoard->ControllerSetup; + break; + } + } + + if (Index >= numVideoBoards) { + HalpVideoBoard = VIDEO_BOARD_UNKNOWN; + HalpVideoChip = VIDEO_CHIP_UNKNOWN; + HalpDisplayControllerSetup = HalpVGASetup; + + // + // let's see, if the bios emulator can initialize the card .... + // + + HalpDisplayWidth = 80; + HalpDisplayText = 25; + return TRUE; + } + + // + // Initialize the display controller. + // + + HalpDisplayControllerSetup(); + + HalpFirstBoot = FALSE; + + return TRUE; +} + +BOOLEAN +HalpInitializeDisplay1 ( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ) + +/*++ + +Routine Description: + + This routine normally allocates pool for the OEM font file, but + in this version we use only VGA facilities of the Grapgic boards + so we simply return TRUE + +Arguments: + + LoaderBlock - Supplies a pointer to the loader parameter block. + +Return Value: + + TRUE + +--*/ + +{ + + return TRUE; +} + +VOID +HalAcquireDisplayOwnership ( + IN PHAL_RESET_DISPLAY_PARAMETERS ResetDisplayParameters + ) + +/*++ + +Routine Description: + + This routine switches ownership of the display away from the HAL to + the system display driver. It is called when the system has reached + a point during bootstrap where it is self supporting and can output + its own messages. Once ownership has passed to the system display + driver any attempts to output messages using HalDisplayString must + result in ownership of the display reverting to the HAL and the + display hardware reinitialized for use by the HAL. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + + // + // Set HAL ownership of the display to false. + // + + HalpDisplayOwnedByHal = FALSE; + HalpReturnToVga = ResetDisplayParameters; + return; +} + +VOID +HalpDoNoSetup( + VOID + ) +/*++ + +Routine Description: + + This routine does nothing... + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + HalpDisplayOwnedByHal = TRUE; + return; +} + +VOID +HalpVGASetup( + VOID + ) +/*++ + +Routine Description: + + This routine initializes a VGA based Graphic card + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + UCHAR byte; + + HalpVGAControlBase = (PVOID)HalpEisaControlBase; + VideoBuffer = ( PUSHORT)( EISA_MEMORY_BASE + 0xb8000); + FontBuffer = ( PUCHAR )( EISA_MEMORY_BASE + 0xa0000); + + // + // if "only" VGA is detected look for an S3 or cirrus chip (VGA ON ATBUS) + // if the firmware detects an S3 chip, look if this is an 805i (interleave) + // + + + if ((HalpVideoChip == VGA) || (HalpVideoChip == S3)){ + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x1206); // look for Cirrus chips + byte = READ_REGISTER_UCHAR(VGA_SEQ_DATA); // read it back + if (byte != 0x12) { // no cirrus + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x4838); // unlock the S3 regs + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0xa539); // Unlock the SC regs + WRITE_REGISTER_UCHAR(VGA_CRT_IDX, 0x30); // look for s3 chip id + byte = READ_REGISTER_UCHAR(VGA_CRT_DATA) ; // look only for major id + switch (byte & 0xf0){ + case 0xa0: // 801/805 chipset + if (byte == 0xa8) { // the new 805i (interleave) +// DebugPrint(("HAL: Found the new 805i Chip resetting to 805 mode\n")); + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0053); + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0067); + } + case 0x80: + case 0x90: +// DebugPrint(("HAL: Found S3 Chip set - Chip id 0x%x\n",byte)); + HalpVideoChip = S3; + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0038); // lock s3 regs + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0039); // lock more s3 regs + break; + default: DebugPrint(("HAL: This seems to be no S3 Chip\n")); + } + } else { // this may be an cirrus + WRITE_REGISTER_UCHAR(VGA_CRT_IDX, 0x27); // cirrus id reg + byte = READ_REGISTER_UCHAR(VGA_CRT_DATA); + if ((byte & 0xe0) == 0x80) { // look for 100xxxxx +// DebugPrint(("HAL: Found Cirrus Chip set - Chip id 0x%x\n",byte)); + HalpVideoChip = CIRRUS; + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0006); // lock Cirrus extensions + } + } + } + + + switch (HalpVideoChip) { + + case S3: HalpResetS3Chip(); + break; + + case CIRRUS: HalpResetCirrusChip(); + break; + + case VGA_STORM: + HalpResetMatroxStorm(); + break; + + default: ; + } + + HalpInitializeVGADisplay(TEXT_80x50); + + // + // Initialize the current display column, row, and ownership values. + // + + HalpColumn = 0; + HalpRow = 0; + HalpDisplayOwnedByHal = TRUE; + return; +} + +VOID +HalQueryDisplayParameters ( + OUT PULONG WidthInCharacters, + OUT PULONG HeightInLines, + OUT PULONG CursorColumn, + OUT PULONG CursorRow + ) + +/*++ + +Routine Description: + + This routine return information about the display area and current + cursor position. + +Arguments: + + WidthInCharacter - Supplies a pointer to a varible that receives + the width of the display area in characters. + + HeightInLines - Supplies a pointer to a variable that receives the + height of the display area in lines. + + CursorColumn - Supplies a pointer to a variable that receives the + current display column position. + + CursorRow - Supplies a pointer to a variable that receives the + current display row position. + +Return Value: + + None. + +--*/ + +{ + + // + // Set the display parameter values and return. + // + + *WidthInCharacters = HalpDisplayWidth; + *HeightInLines = HalpDisplayText; + *CursorColumn = HalpColumn; + *CursorRow = HalpRow; + return; +} + +VOID +HalSetDisplayParameters ( + IN ULONG CursorColumn, + IN ULONG CursorRow + ) + +/*++ + +Routine Description: + + This routine set the current cursor position on the display area. + +Arguments: + + CursorColumn - Supplies the new display column position. + + CursorRow - Supplies a the new display row position. + +Return Value: + + None. + +--*/ + +{ + + // + // Set the display parameter values and return. + // + + if (CursorColumn > HalpDisplayWidth) { + CursorColumn = HalpDisplayWidth; + } + + if (CursorRow > HalpDisplayText) { + CursorRow = HalpDisplayText; + } + + HalpColumn = CursorColumn; + HalpRow = CursorRow; + return; +} + +VOID +HalDisplayString ( + PUCHAR String + ) + +/*++ + +Routine Description: + + This routine displays a character string on the display screen. + +Arguments: + + String - Supplies a pointer to the characters that are to be displayed. + +Return Value: + + None. + +--*/ + +{ + KIRQL OldIrql; + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + if(HalpIsMulti) KiAcquireSpinLock(&HalpDisplayAdapterLock); + + // + // If ownership of the display has been switched to the system display + // driver, then reinitialize the display controller and revert ownership + // to the HAL. + // + + if (HalpDisplayOwnedByHal == FALSE) { + + if (((HalpVideoBoard == VIDEO_BOARD_UNKNOWN) || (HalpVideoBoard == VGA_GENERIC)) && (HalpReturnToVga != NULL)) { + (HalpReturnToVga)(80,25); + } + HalpDisplayControllerSetup(); + + } + + // display the string + +// if( HalpVideoChip == VIDEO_CHIP_UNKNOWN) { +// ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->printf(String); +// } else { + HalpDisplayVGAString(String); +// } + + if(HalpIsMulti) KiReleaseSpinLock(&HalpDisplayAdapterLock); + + KeLowerIrql(OldIrql); + + return; +} + + +VOID +HalpDisplayVGAString ( + PUCHAR String + ) +{ + while (*String) { + switch (*String) { + case '\n': + HalpNextVGALine(); + break; + case '\r': + HalpColumn = 0; + break; + default: + HalpPutVGACharacter(*String); + if (++HalpColumn == HalpDisplayWidth) { + HalpNextVGALine(); + } + } + ++String; + } + + return; +} + + +VOID +HalpNextVGALine( + VOID + ) +{ + if (HalpRow==HalpDisplayText-1) { + HalpScrollVGADisplay(); + } else { + ++HalpRow; + } + HalpColumn = 0; +} + +VOID +HalpScrollVGADisplay( + VOID + ) + +/*++ + +Routine Description: + + Scrolls the text on the display up one line. + +Arguments: + + None + +Return Value: + + None. + +--*/ + +{ + PUSHORT NewStart; + ULONG i; + + + NewStart = VideoBuffer+HalpDisplayWidth; + MegaMoveMemory((PVOID)VideoBuffer, (PVOID)NewStart, (HalpDisplayText-1)*HalpDisplayWidth*sizeof(USHORT)); + + for (i=(HalpDisplayText-1)*HalpDisplayWidth; i<HalpDisplayText*HalpDisplayWidth; i++) { + VideoBuffer[i] = (REVERSE_ATTRIBUTE << 8) | ' '; + } +} + +VOID +HalpPutVGACharacter( + UCHAR Character + ) +{ + PUSHORT cp = (PUSHORT)VideoBuffer; + int x = HalpColumn; + int y = HalpRow; + + cp[y*HalpDisplayWidth + x] = (USHORT)((REVERSE_ATTRIBUTE << 8) | (Character )); +} + + +VOID +HalpClearVGADisplay( + VOID + ) +{ + ULONG i; + PUSHORT cp = (PUSHORT)VideoBuffer; + USHORT Attribute = (REVERSE_ATTRIBUTE << 8) | ' '; + + for(i=0; i < HalpDisplayText*HalpDisplayWidth; i++) { + VideoBuffer[i] = Attribute; + } + + HalpColumn=0; + HalpColumn=0; +} + + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + HARDWARE specific Part of Display routines + + this part of this file deals with special Hardware parts of some + graphic adapters (RamDac, Clock Generator, VGA Chipsets etc. + +-------------------------------------------------------------------*/ + +VOID +DownLoadVGAFont( + VOID + ) +/*+++ + + The Space occupied for 1 caracter in the charackter generator memory of an VGA + is 0x20 bytes, The font itself uses only 8 bytes, so we skip over the difference + +---*/ +{ + + PUCHAR dst = (PUCHAR)FontBuffer; + PUCHAR src = (PUCHAR)font_8x8; + long i, count = 256; + + INIT_VGA_FONT(); + + while(count--){ + for (i=0; i<8; i++) + *dst++ = *src++; + dst += 0x18; + } + EXIT_VGA_FONT() ; +} + +VOID +HalpInitializeVGADisplay( + TEXT_MODE TextMode + ) +{ + +static UCHAR _80x50_crt_regs [MAX_CRT] = { // 80x50 text mode + 0x5f, 0x4f, 0x50, 0x82, 0x55, // cr0 - cr4 + 0x81, 0xBF, 0x1f, 0x0, 0x47, // cr9 - 7 lines per char + 0x20, 0x00, 0x00, 0x00, 0x00, // cra - cursor off + 0x00, 0x9c, 0x8e, 0x8f, 0x28, + 0x1f, 0x96, 0xb9, 0xa3, 0xff + }; + +static UCHAR _132x50_crt_regs [MAX_CRT] = { // 132x50 text mode + 0xa0, 0x83, 0x84, 0x83, 0x8a, // cr0 - cr4 + 0x9e, 0xBF, 0x1f, 0x0, 0x47, // cr9 - 7 lines per char + 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x9c, 0x85, 0x8f, 0x42, + 0x1f, 0x95, 0xa5, 0xa3, 0xff + }; + +static UCHAR default_graph_regs[GRAPH_MAX] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x0e, 0x00, 0xff + }; + +static UCHAR default_pal_regs[MAX_PALETTE] = { + 0x00, 0x01, 0x02, 0x03, 0x04, + 0x05, 0x14, 0x7, 0x38, 0x39, + 0x3A, 0x3B, 0x3C, 0x3d, 0x3e, + 0x3f, 0x08, 0x00, 0x0f, 0x00, + 0x00 + }; + + int i; + UCHAR byte; + + // + // Matrox modification : (cf I/O space mapping p 3.9 of MGA STORM specification) + // PCI convention states that i/o space should only be accessed in bytes) + // + + // + // VGA_MISC : 25.xxx MHZ frequency -> 640 horizontal pixels (val = 63) + // VGA_MISC : 28.xxx MHZ frequency -> 720 horizontal pixels (val = 67) + // + + if (HalpVideoChip == VGA_STORM) WRITE_REGISTER_UCHAR(VGA_MISC_WRITE, 0x67) ; // else little frame + + // reset ATC FlipFlop + byte = READ_REGISTER_UCHAR(VGA_ATC_FF); + WRITE_REGISTER_UCHAR(VGA_ATC_DATA, 0); // Disable palette + + // stop the sequencer + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0100); + + if (HalpVideoChip != VGA_STORM) { + if (TextMode == TEXT_132x50) { + // external clock (40MHz) + WRITE_REGISTER_UCHAR(VGA_MISC_WRITE, 0xAF); + } else { + // COLOR registers , enable RAM, 25 MHz 400 Lines, + WRITE_REGISTER_UCHAR(VGA_MISC_WRITE, 0x63) ; + } + } + + // Select the timing sequencer values + // 8 dot/char + + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0101); + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0302); + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0003); + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0204); + + // start the sequencer + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0300); + + // Unprotect CRT regs and program them + + WRITE_REGISTER_USHORT(VGA_CRT_IDX , 0x0011); + + for(i=0; i<MAX_CRT; i++) { + WRITE_REGISTER_UCHAR(VGA_CRT_IDX, i); + if (TextMode == TEXT_132x50){ + WRITE_REGISTER_UCHAR(VGA_CRT_DATA, _132x50_crt_regs[i]); + } else { + WRITE_REGISTER_UCHAR(VGA_CRT_DATA, _80x50_crt_regs[i]); + } + } + + DownLoadVGAFont(); + + HalpDisplayWidth = (TextMode == TEXT_132x50) ? 132 : 80; + HalpDisplayText = 50; + + HalpClearVGADisplay(); + + i = READ_REGISTER_UCHAR(VGA_ATC_FF); // Reset attr FF + + if (!HalpFirstBoot) { + + // + // if this is not the First Boot + // i.e. an Bugcheck; we have to setup + // the Attribute and colors of the VGA PART + // + + for(i=0; i<GRAPH_MAX; i++) { + WRITE_REGISTER_UCHAR(VGA_GRAPH_IDX , i); + WRITE_REGISTER_UCHAR(VGA_GRAPH_DATA, default_graph_regs[i]); + } + + for(i=0; i<MAX_PALETTE; i++) { // PALETTE (ATC) + WRITE_REGISTER_UCHAR(VGA_ATC_IDX , i); + WRITE_REGISTER_UCHAR(VGA_ATC_DATA, default_pal_regs[i]); + } + + + } + + WRITE_REGISTER_UCHAR(VGA_DAC_MASK , 0xff); + + // + // set the 16 base colors for text mode in the DAC + // + + WRITE_REGISTER_UCHAR(VGA_DAC_WRITE_INDEX, 0x00); + for(i=0; i<48; i++) { + WRITE_REGISTER_UCHAR(VGA_DAC_DATA, base_colors[i]); + } + + WRITE_REGISTER_UCHAR(VGA_ATC_IDX, 0x20); + + WRITE_REGISTER_UCHAR(VGA_SEQ_IDX, 0x01); // Screen on + byte = READ_REGISTER_UCHAR(VGA_SEQ_DATA); + WRITE_REGISTER_UCHAR(VGA_SEQ_DATA, (byte & 0xdf)); // in the sequencer +} + +VOID +HalpMgaWaitLock( + UCHAR clock, + UCHAR p + ) +{ +UCHAR tmpByte; + + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_INDEX,STORM_TVP3026_PLL_ADDR); + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_DATA,0xea); + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_INDEX,clock); + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_DATA,(p & 0x7f)); + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_INDEX,STORM_TVP3026_PLL_ADDR); + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_DATA,0xea); + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_INDEX,clock); + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_DATA,p ); + KeStallExecutionProcessor(10); + + tmpByte = 0; + while (!(tmpByte & 0x40)) { + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_INDEX,clock); + tmpByte = READ_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_DATA); + KeStallExecutionProcessor(10); + } + +} + + +VOID +HalpResetMatroxStorm( + VOID + ) +/*++ + +Routine Description: + + This routine initializes the VGA part of an Matrox storm card + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + USHORT buffer[8]; + UCHAR tmpByte; + + if (!HalpMgaStormBase) { + for(HalpMatroxBus=0;HalpMatroxBus<32;++HalpMatroxBus) { + + for(HalpMatroxSlot=0;HalpMatroxSlot<32;++HalpMatroxSlot) { + + HalpReadPCIConfig(HalpMatroxBus,HalpMatroxSlot,&buffer,0,14); + + if ((buffer[0] == 0x102b) && (buffer[1] == 0x0519) && (buffer[5] == 0x0300)) { + HalpReadPCIConfig(HalpMatroxBus,HalpMatroxSlot,&HalpMgaStormBase,0x10,4); + break; + + } + } + if (HalpMgaStormBase) break; + } + } + if ( HalpMgaStormBase == (ULONG)0) return; + + // tranlated address + HalpMgaStormBase |= 0xa0000000; + + /*** wait for the drawing engine to be idle ***/ + tmpByte = 0; + while (tmpByte & 0x01) tmpByte = READ_REGISTER_UCHAR(HalpMgaStormBase + STORM_OFFSET + STORM_STATUS + 2); + + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_OFFSET + STORM_MISC_W, 0x67); + + if (HalpFirstBoot) { + HalpReadPCIConfig(HalpMatroxBus,HalpMatroxSlot,&Halpval40,STORM_PCI_OPTION,4); + } else { + // interleave bit is reset - gclk not divided - VGA io locations decoded + HalpSetPCIData(HalpMatroxBus,HalpMatroxSlot,(PUCHAR)(&Halpval40),STORM_PCI_OPTION,4); + } + + if (!HalpFirstBoot) { + + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_OFFSET +STORM_MISC_W, 0x2f); + + /*** first : reset (especially for cursor...) ***/ + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_INDEX,STORM_TVP3026_PLL_RESET); + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_DATA,0); + + /*** like fw -> pgm clocks (50Mhz) ***/ + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_OFFSET +STORM_MISC_W, 0x2f); // to pgm PLL + + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_INDEX,STORM_TVP3026_PLL_ADDR); + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_DATA,0); + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_INDEX,STORM_TVP3026_PIX_CLK_DATA); + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_DATA,0xfd); + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_INDEX,STORM_TVP3026_PIX_CLK_DATA); + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_DATA,0x3a); + HalpMgaWaitLock(STORM_TVP3026_PIX_CLK_DATA,0xb2); + + + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_INDEX,STORM_TVP3026_MCLK_CTL); + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_DATA,0x0); + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_INDEX,STORM_TVP3026_MCLK_CTL); + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_DATA,0x8); + + + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_INDEX,STORM_TVP3026_PLL_ADDR); + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_DATA,0); + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_INDEX,STORM_TVP3026_MEM_CLK_DATA); + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_DATA,0xfd); + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_INDEX,STORM_TVP3026_MEM_CLK_DATA); + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_DATA,0x3a); + HalpMgaWaitLock(STORM_TVP3026_MEM_CLK_DATA,0xb2); + + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_INDEX,STORM_TVP3026_MCLK_CTL); + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_DATA,0x10); + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_INDEX,STORM_TVP3026_MCLK_CTL); + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_RAMDAC_OFFSET + STORM_TVP3026_DATA,0x18); + + WRITE_REGISTER_UCHAR (HalpMgaStormBase + STORM_OFFSET + STORM_MISC_W, 0x67); // VGA clock 25.xxxMhz + + WRITE_REGISTER_UCHAR(VGA_CRTCEXT_IDX , VGA_CRTCEXT0); + WRITE_REGISTER_UCHAR(VGA_CRTCEXT_DATA, 0); + WRITE_REGISTER_UCHAR(VGA_CRTCEXT_IDX , VGA_CRTCEXT1); + WRITE_REGISTER_UCHAR(VGA_CRTCEXT_DATA, 0); + WRITE_REGISTER_UCHAR(VGA_CRTCEXT_IDX , VGA_CRTCEXT2); + WRITE_REGISTER_UCHAR(VGA_CRTCEXT_DATA, 0); + WRITE_REGISTER_UCHAR(VGA_CRTCEXT_IDX , VGA_CRTCEXT3); + WRITE_REGISTER_UCHAR(VGA_CRTCEXT_DATA, 0); + WRITE_REGISTER_UCHAR(VGA_CRTCEXT_IDX , VGA_CRTCEXT4); + WRITE_REGISTER_UCHAR(VGA_CRTCEXT_DATA, 0); + WRITE_REGISTER_UCHAR(VGA_CRTCEXT_IDX , VGA_CRTCEXT5); + WRITE_REGISTER_UCHAR(VGA_CRTCEXT_DATA, 0); + } + +} + + +VOID +HalpResetS3Chip( + VOID + ) +/*+++ + + This function resets/loads default values to the S3 Chip + extended registers + + this code is borrowed/derived from the s3 miniport driver + +---*/ +{ + UCHAR byte; + + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x4838); // unlock the S3 regs + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0xa539); // Unlock the SC regs + + WRITE_REGISTER_UCHAR(VGA_SEQ_IDX, 0x01); // Screen off + byte = READ_REGISTER_UCHAR(VGA_SEQ_DATA); + WRITE_REGISTER_UCHAR(VGA_SEQ_DATA, (byte | 0x20)); // stop the sequencer + + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0140); // Enable the enhanced 8514 registers + WRITE_REGISTER_USHORT(S3_ADVFUNC_CNTL, 0x02); // reset to normal VGA operation + + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0032); // Backward Compat 3 + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0035); // CRTC Lock + + WRITE_REGISTER_UCHAR(VGA_SEQ_IDX, 0x00); // async reset + WRITE_REGISTER_UCHAR(VGA_SEQ_DATA, 0x01); // + + WRITE_REGISTER_UCHAR(VGA_FEAT_CNTRL, 0x00); // normal sync + WRITE_REGISTER_UCHAR(VGA_MISC_READ, 0x00); // + + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x8531); + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x2033); // Backward Compat 2 + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0034); // Backward Compat 3 + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x853a); // S3 Misc 1 + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x5a3b); // Data Transfer Exec Pos + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x103c); // Interlace Retrace start + + WRITE_REGISTER_UCHAR(VGA_SEQ_IDX, 0x00); // start the sequencer + WRITE_REGISTER_UCHAR(VGA_SEQ_DATA, 0x03); // + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0xa640); // VLB: 3Wait + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x1841); + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0050); + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0051); + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0xff52); + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0053); + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x3854); + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0055); + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0056); + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0057); + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x8058); // ISA Latch ? (bit 3) + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x005c); + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x005d); + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x005e); + + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0760); + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x8061); + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0xa162); + + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0043); // Extended Mode + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0045); // HW graphics Cursor Mode + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0046); // HW graphics Cursor Orig x + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0xff47); // HW graphics Cursor Orig x + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0xfc48); // HW graphics Cursor Orig y + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0xff49); // HW graphics Cursor Orig y + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0xff4a); // HW graphics Cursor Orig y + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0xff4b); // HW graphics Cursor Orig y + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0xff4c); // HW graphics Cursor Orig y + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0xff4d); // HW graphics Cursor Orig y + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0xff4e); // Dsp Start x pixel pos + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0xdf4f); // Dsp Start y pixel pos + + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0042); // select default clock + + WRITE_REGISTER_UCHAR(VGA_MISC_WRITE, 0x63); // Clock select +/* +// this should be done in the InitializeVGA code ... + + WRITE_REGISTER_UCHAR(VGA_SEQ_IDX, 0x01); // Screen on + byte = READ_REGISTER_UCHAR(VGA_SEQ_DATA); + WRITE_REGISTER_UCHAR(VGA_SEQ_DATA, (byte & 0xdf)); // in the sequencer +*/ + + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0038); // lock s3 regs + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0039); // lock more s3 regs + +} + +VOID +HalpResetCirrusChip( + VOID + ) +/*+++ + + This function resets/loads default values to the Cirrus Chip + extended registers for use with extended text mode (80x50) + + Register values found in the cirrus manual, appendix D5 + +---*/ +{ + UCHAR byte; + + WRITE_REGISTER_UCHAR(VGA_SEQ_IDX, 0x01); // Screen off + byte = READ_REGISTER_UCHAR(VGA_SEQ_DATA); + WRITE_REGISTER_UCHAR(VGA_SEQ_DATA, (byte | 0x20)); // stop the sequencer + + // extended sequencer and crtc regs for cirrus + + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x1206); // unlock the extended registers + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0007); + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x4008); + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x5709); + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x180a); + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x660b); + + // new modifs + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x3b1b); + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x000f); + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0016); + WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x001b); + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0007); + WRITE_REGISTER_USHORT(VGA_GRAPH_IDX, 0x0009); + WRITE_REGISTER_USHORT(VGA_GRAPH_IDX, 0x000a); + WRITE_REGISTER_USHORT(VGA_GRAPH_IDX, 0x000b); + // end new modifs + + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0010); + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0011); + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0012); + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0013); + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0018); + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0119); + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x001a); + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x3b1b); + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x2f1c); + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x301d); + WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x331e); + +} diff --git a/private/ntos/nthals/halsnip/mips/snihalp.h b/private/ntos/nthals/halsnip/mips/snihalp.h new file mode 100644 index 000000000..9bfc31e99 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/snihalp.h @@ -0,0 +1,422 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/snihalp.h,v 1.5 1996/03/12 14:56:20 pierre Exp $") +/*++ + +Copyright (c) 1991-1993 Microsoft Corporation + +Module Name: + + SNIhalp.h, original file jxhalp.h + +Abstract: + + This header file defines the private Hardware Architecture Layer (HAL) + SNI specific interfaces, defines and structures. + + +--*/ + +#ifndef _SNIHALP_ +#define _SNIHALP_ +#include "SNIdef.h" + +// +// Determine if an virtual address is really a physical address. +// + +#define HALP_IS_PHYSICAL_ADDRESS(Va) \ + ((((ULONG)Va >= KSEG0_BASE) && ((ULONG)Va < KSEG2_BASE)) ? TRUE : FALSE) + +#define IS_KSEG0_ADDRESS(Va) \ + ((((ULONG)Va >= KSEG0_BASE) && ((ULONG)Va < KSEG1_BASE)) ? TRUE : FALSE) + +#define IS_KSEG1_ADDRESS(Va) \ + ((((ULONG)Va >= KSEG1_BASE) && ((ULONG)Va < KSEG2_BASE)) ? TRUE : FALSE) + +#define KSEG0_TO_KSEG1(Va) { \ + Va &= ~KSEG0_BASE; \ + Va |= KSEG1_BASE; \ + } + +// +// Define global data used to locate the EISA control space and the realtime +// clock registers. +// + +extern PVOID HalpEisaControlBase; +extern PVOID HalpOnboardControlBase; +extern PVOID HalpEisaMemoryBase; +extern PVOID HalpRealTimeClockBase; +extern PVOID HalpEisaMemoryBase; + +extern UCHAR HalpIsMulti; +extern BOOLEAN HalpIsTowerPci; +extern ULONG HalpMpaCacheReplace; // address to be used for cache replace operation. +extern ULONG HalpTwoWayBit; // size of one set for associative cache R5000-R4600-R4700 + +// +// possibly processor types for SNI machines ... +// + +typedef enum _HalpProcessorType { + ORIONSC, // Orion + Writeback secondary cache + MPAGENT, // R4000 + MpAgent + R4x00, // R4000 SC + UNKNOWN // not yet identified (initial value) +} HalpProcessorType; + +// +// Kind of processor of SNI machines +// + +extern HalpProcessorType HalpProcessorId; + +#define HalpR4600 32 +#define HalpR4700 33 +// +// possibly moterboard types for SNI machines ... +// + +typedef enum _MotherBoardType { +// M8022 = 2, // RM400-10 mother board +// M8022D = 3, // RM400-10 mother board (new PCB) +// M8032 = 4, // RM400 Tower +// M8042 = 5, // RM400 Minitower + M8150 = 6, // RM400 PCI Tower +// M8036 = 7, // RM200 Desktop + MinitowerPCI= 8, // minitower PCI + DesktopPCI = 9 // Desktop PCI +} MotherBoardType; + +// +// Kind of Mainboard of SNI machines +// + +extern MotherBoardType HalpMainBoard; + +// +// Define map register translation entry structure. +// + +typedef struct _TRANSLATION_ENTRY { + PVOID VirtualAddress; + ULONG PhysicalAddress; + ULONG Index; +} TRANSLATION_ENTRY, *PTRANSLATION_ENTRY; + +// +// Define adapter object structure. +// + +typedef struct _ADAPTER_OBJECT { + CSHORT Type; + CSHORT Size; + struct _ADAPTER_OBJECT *MasterAdapter; + ULONG MapRegistersPerChannel; + PVOID AdapterBaseVa; + PVOID MapRegisterBase; + ULONG NumberOfMapRegisters; + ULONG CommittedMapRegisters; + struct _WAIT_CONTEXT_BLOCK *CurrentWcb; + KDEVICE_QUEUE ChannelWaitQueue; + PKDEVICE_QUEUE RegisterWaitQueue; + LIST_ENTRY AdapterQueue; + KSPIN_LOCK SpinLock; + PRTL_BITMAP MapRegisters; + PUCHAR PagePort; + UCHAR ChannelNumber; + UCHAR AdapterNumber; + USHORT DmaPortAddress; + UCHAR AdapterMode; + BOOLEAN NeedsMapRegisters; + BOOLEAN MasterDevice; + BOOLEAN Width16Bits; + BOOLEAN ScatterGather; + INTERFACE_TYPE InterfaceType; +} ADAPTER_OBJECT; + +extern PADAPTER_OBJECT MasterAdapterObject; + +extern POBJECT_TYPE *IoAdapterObjectType; + +extern BOOLEAN LessThan16Mb; +extern BOOLEAN HalpEisaDma; + +// +// Map buffer parameters. These are initialized in HalInitSystem +// + +extern PHYSICAL_ADDRESS HalpMapBufferPhysicalAddress; +extern ULONG HalpMapBufferSize; + +// +// Firmware interface +// + +typedef struct { + CHAR (*getchar)(); + PCHAR (*gets)(); + VOID (*printf)(); + PCHAR (*parsefile)(); + VOID (*reinit_slave)(); + ULONG DCU_reserved; + UCHAR ActiveProcessor[4]; + USHORT DCU_reserved_bis; + USHORT EccErrorSimmNum; + ULONG EccErrorAddress; + struct mpmsg_s *MsgPassArea; + struct bank *MemConfArea; + ULONG NbMemBanks; + ULONG scram_ctlr; // fw reserved (ram disk) + ULONG (*EipRoutine)(); + ULONG EipContext; + UCHAR EipHalInfo; + UCHAR pad[3]; + ULONG reserved[5]; + } SNI_PRIVATE_VECTOR; + + +// definitions for DCU_reserved_bis + +#define FLAG_ECC_ERROR 1 + + + struct mpmsg_s { + ULONG *mpmsg_wlckp; /* pointer to the writer lock */ + ULONG *mpmsg_bp; /* beginning pointer message[0] */ + ULONG *mpmsg_ep; /* endding pointer message[MPMSG_NMAXMSG] */ + ULONG *mpmsg_rp; /* current read pointer in message[] */ + ULONG *mpmsg_wp; /* current write pointer in message[] */ +}; + + +struct bank { + ULONG total_size; + UCHAR *first_addr; + ULONG first_piece_size; + UCHAR *second_addr; + ULONG second_piece_size; +}; + + + +// +// Define function prototypes. +// + + +ULONG +HalpGetStatusRegister( + VOID + ); + +ULONG +HalpSetStatusRegister( + ULONG Value + ); + +ULONG +HalpGetCauseRegister( + VOID + ); + +ULONG +HalpSetCauseRegister( + ULONG value + ); + +ULONG +HalpGetConfigRegister( + VOID + ); + +ULONG +HalpSetConfigRegister( + ULONG value + ); + +BOOLEAN +HalpMapIoSpace( + VOID + ); + +VOID +HalpInitializePCIBus ( + VOID + ); + +BOOLEAN +HalpCreateIntStructures( + VOID + ); + +BOOLEAN +HalpCreateIntMultiStructures ( + VOID + ); + +BOOLEAN +HalpCreateIntPciStructures ( + VOID + ); + +BOOLEAN +HalpCreateEisaStructures( + IN INTERFACE_TYPE Interface + ); + + +VOID +HalpDisableEisaInterrupt( + IN ULONG Vector + ); + +VOID +HalpDisableInterrupts( + VOID + ); + +VOID +HalpEnableEisaInterrupt( + IN ULONG Vector, + IN KINTERRUPT_MODE InterruptMode + ); + +VOID +HalpDisableOnboardInterrupt( + IN ULONG Vector + ); + +VOID +HalpEnableOnboardInterrupt( + IN ULONG Vector, + IN KINTERRUPT_MODE InterruptMode + ); + +BOOLEAN +HalpGrowMapBuffers( + PADAPTER_OBJECT AdapterObject, + ULONG Amount + ); + +PADAPTER_OBJECT +HalpAllocateAdapter( + IN ULONG MapRegistersPerChannel, + IN PVOID AdapterBaseVa, + IN PVOID MapRegisterBase + ); + +ULONG +HalpAllocPhysicalMemory( + IN PLOADER_PARAMETER_BLOCK LoaderBlock, + IN ULONG MaxPhysicalAddress, + IN ULONG NoPages, + IN BOOLEAN bAlignOn64k + ); + +BOOLEAN +HalpPciInt0Dispatch( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ); + +BOOLEAN +HalpPciTowerInt0Dispatch( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ); + + +BOOLEAN +HalpPciTowerInt3Dispatch( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ); + + +BOOLEAN +HalpRM200Int0Dispatch( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ); + +BOOLEAN +HalpRM400Int0Dispatch( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ); + +BOOLEAN +HalpRM400TowerInt0Dispatch( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ); + +BOOLEAN +HalpInt1Dispatch( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ); + +BOOLEAN +HalpRM400Int3Process ( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ); + +BOOLEAN +HalpRM400Int4Process ( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ); + +BOOLEAN +HalpRM400Int5Process ( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ); + +VOID +HalpSystemInit( + VOID + ); + +VOID +HalpDisplayCopyRight( + VOID + ); + +VOID +HalpClearVGADisplay( + VOID + ); + +VOID +HalpIpiInterrupt( + VOID + ); + +VOID +HalpInitMPAgent( + ULONG Number + ); + +ULONG +HalpProcIdentify( + VOID + ); + +BOOLEAN +HalpPciEccCorrector( + ULONG Addr, + ULONG Pfn, + ULONG Length + ); + +BOOLEAN +HalpMultiPciEccCorrector( + ULONG Addr, + ULONG Pfn, + ULONG Length + ); + +#endif // _SNIHALP_ diff --git a/private/ntos/nthals/halsnip/mips/snipbus.c b/private/ntos/nthals/halsnip/mips/snipbus.c new file mode 100644 index 000000000..0fb0d1063 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/snipbus.c @@ -0,0 +1,2051 @@ +/*++ + + +Copyright (c) 1989 Microsoft Corporation +Copyright (c) 1994 Digital Equipment Corporation + +Module Name: + + pcisup.c + +Abstract: + + Platform-independent PCI bus routines + +Author: + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#include "halp.h" +#include "snipci.h" +#include "snipbus.h" +#include "pci.h" +#include "eisa.h" + +UCHAR HalpInterruptLine[10][32]; + +// +// Define PCI slot validity +// +typedef enum _VALID_SLOT { + InvalidBus = 0, + InvalidSlot, + ValidSlot +} VALID_SLOT; + +// +// Local prototypes for routines supporting HalpGet/SetPCIData +// + +VOID +HalpReadPCIConfig ( + IN ULONG BusNumber, + IN PCI_SLOT_NUMBER Slot, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +VOID +HalpWritePCIConfig ( + IN ULONG BusNumber, + IN PCI_SLOT_NUMBER Slot, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +VALID_SLOT +HalpValidPCISlot ( + IN ULONG BusNumber, + IN PCI_SLOT_NUMBER Slot + ); + +BOOLEAN +HalpPCIConfigPartialRead( + IN ULONG Offset, + IN ULONG Length, + IN PUCHAR Buffer + ); + +VOID +HalpPCIConfigPartialWrite( + IN ULONG Offset, + IN ULONG Length, + IN PUCHAR Buffer + ); + +PCI_CONFIGURATION_TYPES +HalpPCIConfigCycleType ( + IN ULONG BusNumber, + IN PCI_SLOT_NUMBER Slot + ); + +VOID +HalpIntLineUpdate( + IN ULONG BusNumber, + IN ULONG Slot, + PPCI_COMMON_CONFIG PciData + ); + +BOOLEAN HalpTowerTestConf( + IN ULONG BusNumber, + IN PCI_SLOT_NUMBER Slot +); + +// +// Pragmas to assign functions to different kinds of pages. +// + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT,HalpInitializePCIBus) +#endif // ALLOC_PRAGMA + + +// +// Globals +// + +KSPIN_LOCK HalpPCIConfigLock; +extern BOOLEAN HalPCIRegistryInitialized; +ULONG PCIMaxBuses; +ULONG PCIMaxLocalDevice; +ULONG PCIMaxDevice; +ULONG PCIMaxBusZeroDevice; +PULONG HalpPciConfigAddr; +PULONG HalpPciConfigData; +UCHAR HalpIntAMax; +UCHAR HalpIntBMax; +UCHAR HalpIntCMax; +UCHAR HalpIntDMax; + +// +// Registry stuff +// + +PCWSTR rgzMultiFunctionAdapter = L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter"; +PCWSTR rgzConfigurationData = L"Configuration Data"; +PCWSTR rgzIdentifier = L"Identifier"; +PCWSTR rgzPCIIdentifier = L"PCI"; + + + +/*++ + +Routine Description: + + This function looks at the registry to find if the current machine + has a PCI bus or not. + + The Arc firmware is responsible for building configuration information + about the number of PCI buses on the system and nature (local vs. secondary + - across a PCI-PCI bridge) of the each bus. This state is held in + PCIRegInfo. + +Arguments: + + None. + + +Return Value: + + None. + +--*/ + + +VOID +HalpRecurseLoaderBlock( + IN PCONFIGURATION_COMPONENT_DATA CurrentEntry + ) +/*++ + +Routine Description: + + This routine parses the loader parameter block looking for the PCI + node. Once found, used to determine if PCI parity checking should be + enabled or disabled. Set the default to not disable checking. + +Arguments: + + CurrentEntry - Supplies a pointer to a loader configuration + tree or subtree. + +Return Value: + + None. + +--*/ +{ + + PCONFIGURATION_COMPONENT Component; + PPCI_REGISTRY_INFO PCIRegInfo = NULL; + PCM_PARTIAL_RESOURCE_DESCRIPTOR HalpDesc; + + if (CurrentEntry) { + Component = &CurrentEntry->ComponentEntry; + + if (Component->Class == AdapterClass && + Component->Type == MultiFunctionAdapter) { + + if (strcmp(Component->Identifier, "PCI") == 0) { +#if DBG + HalDisplayString("PCI Machine detected\n"); +#endif + HalpDesc = ((PCM_PARTIAL_RESOURCE_LIST)(CurrentEntry->ConfigurationData))->PartialDescriptors; + if (HalpDesc->Type == CmResourceTypeDeviceSpecific) { + PCIRegInfo = (PPCI_REGISTRY_INFO) (HalpDesc+1); + PCIMaxBuses = PCIRegInfo->NoBuses; + HalPCIRegistryInitialized = TRUE; + } + return; + } + } + + // + // Process all the Siblings of current entry + // + + HalpRecurseLoaderBlock(CurrentEntry->Sibling); + + // + // Process all the Childeren of current entry + // + + HalpRecurseLoaderBlock(CurrentEntry->Child); + + } +} + +VOID +HalpParseLoaderBlock( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ) +{ + + if (LoaderBlock == NULL) { + return; + } + HalpRecurseLoaderBlock( (PCONFIGURATION_COMPONENT_DATA) + LoaderBlock->ConfigurationRoot); +} + + +/*++ + +Routine Description: + + The function intializes global PCI bus state from execpt those from the registry. + + The maximum virtual slot number on the local (type 0 config cycle) + PCI bus is registered here, based on the machine dependent define + PCI_MAX_LOCAL_DEVICE. This state is carried in PCIMaxLocalDevice. + + The maximum number of virtual slots on a secondary bus is fixed by the + PCI Specification and is represented by PCI_MAX_DEVICES. This + state is held in PCIMaxDevice. + +Arguments: + + None. + +Return Value: + + None. + + +--*/ + +VOID +HalpInitializePCIBus ( + VOID + ) + +{ + ULONG irqsel, iomemconf; + + PCIMaxLocalDevice = PCI_MAX_DEVICES - 1; + PCIMaxDevice = PCI_MAX_DEVICES - 1; + + if (HalpIsTowerPci) { + PCIMaxBusZeroDevice = PCI_MAX_DEVICES - 1; + } else { + PCIMaxBusZeroDevice = 7; + } + + KeInitializeSpinLock (&HalpPCIConfigLock); + + // + // Specific sni init to distinguish between desktop/minitower and tower ASIC + // + + if (HalpIsTowerPci) HalpPciConfigAddr = (PULONG) (PCI_TOWER_CONF_ADDR_REGISTER); + else HalpPciConfigAddr = (PULONG) (PCI_CONF_ADDR_REGISTER); + HalpPciConfigData = (PULONG)(PCI_IO_BASE | 0xcfc); + + HalpIntAMax = INTA_VECTOR ; + HalpIntBMax = INTB_VECTOR ; + HalpIntCMax = INTC_VECTOR ; + HalpIntDMax = INTD_VECTOR ; + + // enable PCI timeout interrupts + + if (!HalpIsTowerPci) { + iomemconf = READ_REGISTER_ULONG(PCI_IOMEMCONF_REGISTER); + WRITE_REGISTER_ULONG( PCI_IOMEMCONF_REGISTER , + (iomemconf & (~PCI_IOMEMCONF_ENIOTMOUT))); // clear it + // reenable timeout + enable ECC detector-corrector + WRITE_REGISTER_ULONG( PCI_IOMEMCONF_REGISTER , iomemconf | PCI_IOMEMCONF_ENCHKECC); + irqsel = READ_REGISTER_ULONG(PCI_IRQSEL_REGISTER); + WRITE_REGISTER_ULONG( PCI_IRQSEL_REGISTER , + ((irqsel | PCI_IRQSEL_MASK ) & PCI_IRQSEL_INT)); + } else { + // init ECC single counter to autorize 0xffff single ECC errors before system crash + WRITE_REGISTER_ULONG (PCI_TOWER_MEM_CONTROL_1, (READ_REGISTER_ULONG(PCI_TOWER_MEM_CONTROL_1) & ERROR_COUNTER_MASK) | ERROR_COUNTER_INITVALUE); + } + +} + + + +/*++ + +Routine Description: + + The function returns the PCI bus data for a device. + +Arguments: + + BusNumber - Indicates which bus. + + VendorSpecificDevice - The VendorID (low Word) and DeviceID (High Word) + + Buffer - Supplies the space to store the data. + + Length - Supplies a count in bytes of the maximum amount to return. + +Return Value: + + Returns the amount of data stored into the buffer. + + If this PCI slot has never been set, then the configuration information + returned is zeroed. + + +--*/ + +ULONG +HalpGetPCIData ( + IN ULONG BusNumber, + IN ULONG Slot, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ) + +{ + PPCI_COMMON_CONFIG PciData; + UCHAR iBuffer[PCI_COMMON_HDR_LENGTH]; + ULONG Len; + PCI_SLOT_NUMBER PciSlot; + ULONG j; + + if (Length > sizeof (PCI_COMMON_CONFIG)) { + Length = sizeof (PCI_COMMON_CONFIG); + } + + Len = 0; + PciData = (PPCI_COMMON_CONFIG) iBuffer; + PciSlot = *((PPCI_SLOT_NUMBER) &Slot); + + if (Offset >= PCI_COMMON_HDR_LENGTH) { + + // + // The user did not request any data from the common + // header. Verify the PCI device exists, then continue + // in the device specific area. + // + + HalpReadPCIConfig (BusNumber, PciSlot, PciData, 0, sizeof(ULONG)); + + // + // Check for non-existent bus + // + + if (PciData->VendorID == 0x00) { + return 0; // Requested bus does not exist. Return no data. + } + + // + // Check for invalid slot + // + + if (PciData->VendorID == PCI_INVALID_VENDORID) { + if ((Offset == 0) && (Length >=2)) *(PUSHORT)Buffer = PCI_INVALID_VENDORID; + return 2; + } + + + } else { + + // + // Caller requested at least some data within the + // common header. Read the whole header, effect the + // fields we need to and then copy the user's requested + // bytes from the header + // + + // + // Read this PCI devices slot data + // + + Len = PCI_COMMON_HDR_LENGTH; + HalpReadPCIConfig (BusNumber, PciSlot, PciData, 0, Len); + + // + // Check for non-existent bus + // + + if (PciData->VendorID == 0x00) { + return 0; // Requested bus does not exist. Return no data. + } + + // + // Check for invalid slot + // + + if (PciData->VendorID == PCI_INVALID_VENDORID || + PCI_CONFIG_TYPE (PciData) != 0) { + if ((Offset == 0) && (Length >=2)) *(PUSHORT)Buffer = PCI_INVALID_VENDORID; + return 2; // only return invalid id + } + + // + // Update interrupt line + // + + HalpIntLineUpdate(BusNumber, Slot, PciData); + + // + // Pb concerning especially SCSI : skip IO address when = 3bf0000 + // + + for (j=0; j < PCI_TYPE0_ADDRESSES; j++) { + + if ( (((ULONG)(PciData->u.type0.BaseAddresses[j]) & ~0x3) | 0x01) == 0x3bf0001 ) + PciData->u.type0.BaseAddresses[j] = 0; + } + + // + // Copy whatever data overlaps into the callers buffer + // + + if (Len < Offset) { + // no data at caller's buffer + return 0; + } + + Len -= Offset; + if (Len > Length) { + Len = Length; + } + + RtlMoveMemory(Buffer, iBuffer + Offset, Len); + + Offset += Len; + Buffer += Len; + Length -= Len; + + } + + if (Length) { + + if (Offset >= PCI_COMMON_HDR_LENGTH) { + + // + // The remaining Buffer comes from the Device Specific + // area - put on the kitten gloves and read from it. + // + // Specific read/writes to the PCI device specific area + // are guarenteed: + // + // Not to read/write any byte outside the area specified + // by the caller. (this may cause WORD or BYTE references + // to the area in order to read the non-dword aligned + // ends of the request) + // + // To use a WORD access if the requested length is exactly + // a WORD long. + // + // To use a BYTE access if the requested length is exactly + // a BYTE long. + // + + HalpReadPCIConfig (BusNumber, PciSlot, Buffer, Offset, Length); + Len += Length; + + } + + } + + return Len; +} + + +/*++ + +Routine Description: + + The function returns the Pci bus data for a device. + +Arguments: + + + VendorSpecificDevice - The VendorID (low Word) and DeviceID (High Word) + + Buffer - Supplies the space to store the data. + + Length - Supplies a count in bytes of the maximum amount to return. + +Return Value: + + Returns the amount of data stored into the buffer. + +--*/ + +ULONG +HalpSetPCIData ( + IN ULONG BusNumber, + IN ULONG Slot, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ) + +{ + PPCI_COMMON_CONFIG PciData, PciData2; + UCHAR iBuffer[PCI_COMMON_HDR_LENGTH]; + UCHAR iBuffer2[PCI_COMMON_HDR_LENGTH]; + ULONG Len; + PCI_SLOT_NUMBER PciSlot; + + if (Length > sizeof (PCI_COMMON_CONFIG)) { + Length = sizeof (PCI_COMMON_CONFIG); + } + + + Len = 0; + PciData = (PPCI_COMMON_CONFIG) iBuffer; + PciData2 = (PPCI_COMMON_CONFIG) iBuffer2; + PciSlot = *((PPCI_SLOT_NUMBER) &Slot); + + + if (Offset >= PCI_COMMON_HDR_LENGTH) { + + // + // The user did not request any data from the common + // header. Verify the PCI device exists, then continue in + // the device specific area. + // + + HalpReadPCIConfig (BusNumber, PciSlot, PciData, 0, sizeof(ULONG)); + + if (PciData->VendorID == PCI_INVALID_VENDORID || PciData->VendorID == 0x00) { + return 0; + } + + } else { + + // + // Caller requested to set at least some data within the + // common header. + // + + Len = PCI_COMMON_HDR_LENGTH; + HalpReadPCIConfig (BusNumber, PciSlot, PciData, 0, Len); + + if (PciData->VendorID == PCI_INVALID_VENDORID || + PciData->VendorID == 0x00 || + PCI_CONFIG_TYPE (PciData) != 0) { + // + // no device, or header type unkown + // + return 0; + } + + // + // Copy COMMON_HDR values to buffer2, then overlay callers changes. + // + + RtlMoveMemory (iBuffer2, iBuffer, Len); + + Len -= Offset; + if (Len > Length) { + Len = Length; + } + + RtlMoveMemory (iBuffer2+Offset, Buffer, Len); + + // in case interrupt line or pin was editted + //HalpPCILineToPin (BusNumber, PciSlot, PciData2, PciData); + + + // + // Set new PCI configuration + // + + HalpWritePCIConfig (BusNumber, PciSlot, iBuffer2+Offset, Offset, Len); + + Offset += Len; + Buffer += Len; + Length -= Len; + } + + if (Length) { + + if (Offset >= PCI_COMMON_HDR_LENGTH) { + + // + // The remaining Buffer comes from the Device Specific + // area - put on the kitten gloves and write it + // + // Specific read/writes to the PCI device specific area + // are guarenteed: + // + // Not to read/write any byte outside the area specified + // by the caller. (this may cause WORD or BYTE references + // to the area in order to read the non-dword aligned + // ends of the request) + // + // To use a WORD access if the requested length is exactly + // a WORD long. + // + // To use a BYTE access if the requested length is exactly + // a BYTE long. + // + + HalpWritePCIConfig (BusNumber, PciSlot, Buffer, Offset, Length); + Len += Length; + } + } + + return Len; +} + + +/*++ + +Routine Description: + + + +Arguments: + + + + +Return Value: + + +--*/ + +VOID +HalpReadPCIConfig ( + IN ULONG BusNumber, + IN PCI_SLOT_NUMBER Slot, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ) +{ + KIRQL OldIrql; + PCI_CONFIG_ADDR PciConfigAddrData; + PUCHAR BufferOrg; + ULONG LengthOrg; + ULONG PartialLength; + ULONG irqsel, iomemconf; + BOOLEAN result; + // + // Read the slot, if it's valid. + // Otherwise, return an Invalid VendorId for a invalid slot on an existing bus + // or a null (zero) buffer if we have a non-existant bus. + // + + BufferOrg = Buffer;LengthOrg = Length; + + switch (HalpValidPCISlot (BusNumber, Slot)) { + + case ValidSlot: + + // + // Acquire Spin Lock + // + + KeAcquireSpinLock (&HalpPCIConfigLock, &OldIrql); + + // disable PCI timeout to avoid timeout interrupt when drivers attempt to access invalid slot + + if (!HalpIsTowerPci) { + irqsel = READ_REGISTER_ULONG(PCI_IRQSEL_REGISTER); + WRITE_REGISTER_ULONG( PCI_IRQSEL_REGISTER , + (irqsel & ~PCI_IRQSEL_TIMEOUTMASK)); + } + + // + // Program PciConfigAddr register + // + + PciConfigAddrData.Type = (BusNumber ? PciConfigType1 : PciConfigType0); + PciConfigAddrData.BusNumber = BusNumber; + PciConfigAddrData.DeviceNumber = Slot.u.bits.DeviceNumber; + PciConfigAddrData.FunctionNumber = 0; +// PciConfigAddrData.DeviceNumber = (BusNumber ? Slot.u.bits.DeviceNumber : 0); +// PciConfigAddrData.FunctionNumber = Slot.u.bits.FunctionNumber; + PciConfigAddrData.Reserved = 0; + PciConfigAddrData.Enable = 1; + + // + // Issue PCI Configuration Cycles + // + + if (Offset % 4) { + + PartialLength = (Length > (4 - (Offset % 4))) ? (4 - (Offset % 4)) : Length; + + PciConfigAddrData.RegisterNumber = (Offset - (Offset % 4)) >> 2; // ULONG frontier + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciConfigAddrData)); + + if (HalpIsTowerPci &&( PciConfigAddrData.BusNumber !=0 || PciConfigAddrData.DeviceNumber !=0)) + WRITE_REGISTER_ULONG(PCI_TOWER_MP_BUS_PCI_LOCK,MP_BUS_PCI_LOCK_REQ); + + result = HalpPCIConfigPartialRead((4 - (Offset % 4)),PartialLength, Buffer); + + if (HalpIsTowerPci &&( PciConfigAddrData.BusNumber !=0 || PciConfigAddrData.DeviceNumber !=0)) + WRITE_REGISTER_ULONG(PCI_TOWER_MP_BUS_PCI_LOCK,0); + + if (!result){ + + RtlFillMemory (BufferOrg, LengthOrg, (UCHAR) -1); + + if (!HalpIsTowerPci) { + iomemconf = READ_REGISTER_ULONG(PCI_IOMEMCONF_REGISTER); + WRITE_REGISTER_ULONG( PCI_IOMEMCONF_REGISTER , + (iomemconf & (~PCI_IOMEMCONF_ENIOTMOUT))); // clear it + // reenable timeout + WRITE_REGISTER_ULONG( PCI_IOMEMCONF_REGISTER , iomemconf ); + WRITE_REGISTER_ULONG( PCI_IRQSEL_REGISTER , irqsel ); + } + + KeReleaseSpinLock (&HalpPCIConfigLock, OldIrql); + return; + } + Offset += PartialLength; + Length -= PartialLength; + Buffer += PartialLength; + + } + + while (Length >= 4) { + + PciConfigAddrData.RegisterNumber = Offset >> 2; // ULONG frontier + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciConfigAddrData)); + + if (HalpIsTowerPci &&( PciConfigAddrData.BusNumber !=0 || PciConfigAddrData.DeviceNumber !=0)) + WRITE_REGISTER_ULONG(PCI_TOWER_MP_BUS_PCI_LOCK,MP_BUS_PCI_LOCK_REQ); + + * (PULONG) Buffer = READ_REGISTER_ULONG ((PULONG) HalpPciConfigData); + + if (HalpIsTowerPci && (PciConfigAddrData.BusNumber !=0 || PciConfigAddrData.DeviceNumber !=0)) + WRITE_REGISTER_ULONG(PCI_TOWER_MP_BUS_PCI_LOCK,0); + + if (* (PULONG) Buffer == 0XFFFFFFFF) { + RtlFillMemory (BufferOrg, LengthOrg, (UCHAR) -1); + + if (!HalpIsTowerPci) { + // reenable timeout + iomemconf = READ_REGISTER_ULONG(PCI_IOMEMCONF_REGISTER); + WRITE_REGISTER_ULONG( PCI_IOMEMCONF_REGISTER , + (iomemconf & (~PCI_IOMEMCONF_ENIOTMOUT))); // clear it + // reenable timeout + WRITE_REGISTER_ULONG( PCI_IOMEMCONF_REGISTER , iomemconf ); + WRITE_REGISTER_ULONG( PCI_IRQSEL_REGISTER , irqsel ); + } + + KeReleaseSpinLock (&HalpPCIConfigLock, OldIrql); + return; + } + + Offset += 4; + Buffer += 4; + Length -= 4; + + } + + if ( Length > 0) { + + PciConfigAddrData.RegisterNumber = Offset >> 2; + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciConfigAddrData)); + + if (HalpIsTowerPci &&( PciConfigAddrData.BusNumber !=0 || PciConfigAddrData.DeviceNumber !=0)) + WRITE_REGISTER_ULONG(PCI_TOWER_MP_BUS_PCI_LOCK,MP_BUS_PCI_LOCK_REQ); + + result = HalpPCIConfigPartialRead(0,Length,Buffer); + + if (HalpIsTowerPci &&( PciConfigAddrData.BusNumber !=0 || PciConfigAddrData.DeviceNumber !=0)) + WRITE_REGISTER_ULONG(PCI_TOWER_MP_BUS_PCI_LOCK,0); + + if (!result) { + + RtlFillMemory (BufferOrg, LengthOrg, (UCHAR) -1); + + if (!HalpIsTowerPci) { + // reenable timeout + iomemconf = READ_REGISTER_ULONG(PCI_IOMEMCONF_REGISTER); + WRITE_REGISTER_ULONG( PCI_IOMEMCONF_REGISTER , + (iomemconf & (~PCI_IOMEMCONF_ENIOTMOUT))); // clear it + // reenable timeout + WRITE_REGISTER_ULONG( PCI_IOMEMCONF_REGISTER , iomemconf ); + WRITE_REGISTER_ULONG( PCI_IRQSEL_REGISTER , irqsel ); + } + + KeReleaseSpinLock (&HalpPCIConfigLock, OldIrql); + return; + } + + Offset += Length; + Length -= Length; + Buffer += Length; + + } + + // + // Release Spin Lock + // + + // reenable timeout + + if (!HalpIsTowerPci) { + iomemconf = READ_REGISTER_ULONG(PCI_IOMEMCONF_REGISTER); + WRITE_REGISTER_ULONG( PCI_IOMEMCONF_REGISTER , + (iomemconf & (~PCI_IOMEMCONF_ENIOTMOUT))); // clear it + // reenable timeout + WRITE_REGISTER_ULONG( PCI_IOMEMCONF_REGISTER , iomemconf ); + WRITE_REGISTER_ULONG( PCI_IRQSEL_REGISTER , irqsel ); + } + + KeReleaseSpinLock (&HalpPCIConfigLock, OldIrql); + break; + + case InvalidSlot: + + // + // Invalid SlotID return no data (Invalid Slot ID = 0xFFFF) + // + + RtlFillMemory (Buffer, Length, (UCHAR) -1); + break ; + + case InvalidBus: + + // + // Invalid Bus, return return no data + // + + RtlFillMemory (Buffer, Length, (UCHAR) 0); + break ; + + } + + + return; + +} + + +/*++ + +Routine Description: + + + +Arguments: + + + + +Return Value: + + +--*/ + +VOID +HalpWritePCIConfig ( + IN ULONG BusNumber, + IN PCI_SLOT_NUMBER Slot, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ) +{ + KIRQL OldIrql; + PCI_CONFIG_ADDR PciConfigAddrData; + ULONG PartialLength; + ULONG irqsel, iomemconf; + + if (HalpValidPCISlot (BusNumber, Slot) != ValidSlot) { + + // + // Invalid SlotID do nothing + // + + return ; + } + + + // + // Acquire Spin Lock + // + + KeAcquireSpinLock (&HalpPCIConfigLock, &OldIrql); + + // disable PCI timeout to avoid timeout interrupt when drivers attempt to access invalid slot + + if (!HalpIsTowerPci) { + irqsel = READ_REGISTER_ULONG(PCI_IRQSEL_REGISTER); + WRITE_REGISTER_ULONG( PCI_IRQSEL_REGISTER , + (irqsel & ~PCI_IRQSEL_TIMEOUTMASK)); + } + + + // + // Program PciConfigAddr register + // + + PciConfigAddrData.Type = (BusNumber ? PciConfigType1 : PciConfigType0); + PciConfigAddrData.BusNumber = BusNumber; + PciConfigAddrData.DeviceNumber = Slot.u.bits.DeviceNumber; + PciConfigAddrData.FunctionNumber = 0; +// PciConfigAddrData.DeviceNumber = (BusNumber ? Slot.u.bits.DeviceNumber : 0); +// PciConfigAddrData.FunctionNumber = Slot.u.bits.FunctionNumber; + PciConfigAddrData.Reserved = 0; + PciConfigAddrData.Enable = 1; + + // + // Issue PCI Configuration Cycles + // + + if (Offset % 4) { + + PartialLength = (Length > (4 - (Offset % 4))) ? (4 - (Offset % 4)) : Length; + + PciConfigAddrData.RegisterNumber = (Offset - (Offset % 4)) >> 2; // ULONG frontier + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciConfigAddrData)); + + HalpPCIConfigPartialWrite((4 - (Offset % 4)),PartialLength, Buffer); + + Offset += PartialLength; + Length -= PartialLength; + Buffer += PartialLength; + + } + + while (Length >= 4) { + + PciConfigAddrData.RegisterNumber = Offset >> 2; // ULONG frontier + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciConfigAddrData)); + + WRITE_REGISTER_ULONG ((PULONG) HalpPciConfigData, *((PULONG)Buffer)); + + Offset += 4; + Buffer += 4; + Length -= 4; + + } + + if ( Length > 0) { + + PciConfigAddrData.RegisterNumber = Offset >> 2; + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciConfigAddrData)); + + HalpPCIConfigPartialWrite(0,Length,Buffer); + + Offset += Length; + Length -= Length; + Buffer += Length; + + } + + // + // Release Spin Lock + // + + // reenable timeout + + if (!HalpIsTowerPci) { + iomemconf = READ_REGISTER_ULONG(PCI_IOMEMCONF_REGISTER); + WRITE_REGISTER_ULONG( PCI_IOMEMCONF_REGISTER , + (iomemconf & (~PCI_IOMEMCONF_ENIOTMOUT))); // clear it + // reenable timeout + WRITE_REGISTER_ULONG( PCI_IOMEMCONF_REGISTER , iomemconf ); + WRITE_REGISTER_ULONG( PCI_IRQSEL_REGISTER , irqsel ); + } + + KeReleaseSpinLock (&HalpPCIConfigLock, OldIrql); + + +} + + +/*++ + +Routine Description: + + + +Arguments: + + + + +Return Value: + + +--*/ + +VALID_SLOT +HalpValidPCISlot ( + IN ULONG BusNumber, + IN PCI_SLOT_NUMBER Slot + ) +{ + PCI_SLOT_NUMBER Slot2; + UCHAR HeaderType; + ULONG i; + PCI_CONFIGURATION_TYPES PciConfigType; + + + // + // Get the config cycle type for the proposed bus. + // (PciConfigTypeInvalid indicates a non-existent bus.) + // + + PciConfigType = HalpPCIConfigCycleType(BusNumber, Slot); + + // + // The number of devices allowed on a local PCI bus may be different + // than that across a PCI-PCI bridge. + // + + switch(PciConfigType) { + + case PciConfigType0: + + if ((BusNumber == 0) && (Slot.u.bits.DeviceNumber > PCIMaxBusZeroDevice)) { + + return InvalidSlot; + } + if (Slot.u.bits.DeviceNumber > PCIMaxLocalDevice) { + + return InvalidSlot; + } + break; + + case PciConfigType1: + + if ((BusNumber == 0) && (Slot.u.bits.DeviceNumber > PCIMaxBusZeroDevice)) { + + return InvalidSlot; + } + if (Slot.u.bits.DeviceNumber > PCIMaxDevice) { + + return InvalidSlot; + } + break; + + case PciConfigTypeInvalid: + + return InvalidBus; + + break; + + } + + // + // Check function number + // + + if (Slot.u.bits.FunctionNumber == 0) { + if (HalpTowerTestConf(BusNumber, Slot)) return ValidSlot;else return InvalidSlot; + } + + // + // Non zero function numbers are only supported if the + // device has the PCI_MULTIFUNCTION bit set in it's header + // + + i = Slot.u.bits.DeviceNumber; + + // + // Read DeviceNumber, Function zero, to determine if the + // PCI supports multifunction devices + // + + Slot2 = Slot; + Slot2.u.bits.FunctionNumber = 0; + + if ( ! HalpTowerTestConf(BusNumber, Slot2)) return InvalidSlot; + + HalpReadPCIConfig (BusNumber, + Slot2, + &HeaderType, + FIELD_OFFSET (PCI_COMMON_CONFIG, HeaderType), + sizeof(UCHAR) ); + + if (!(HeaderType & PCI_MULTIFUNCTION) || (HeaderType == 0xFF)) { + + // + // this device doesn't exists or doesn't support MULTIFUNCTION types + // + + return InvalidSlot; + + } + + return ValidSlot; +} + + +/*++ + +Routine Description: + + Partial write in the PCI config space ( less than one ULONG) + +Arguments: + + + + +Return Value: + + +--*/ +VOID +HalpPCIConfigPartialWrite( + IN ULONG Offset, + IN ULONG Length, + IN PUCHAR Buffer + ) +{ + switch(Offset) { + + case 0: + + if (Length > 1) { + WRITE_REGISTER_USHORT ((PULONG) HalpPciConfigData, *(PUSHORT)Buffer); + Buffer +=2;Offset +=2; + } + if (Length !=2) { + WRITE_REGISTER_UCHAR ((PULONG) (((PUCHAR)HalpPciConfigData) + Offset), *Buffer); + ++Buffer; + } + break; + + case 1: + + WRITE_REGISTER_UCHAR ((PULONG) (((PUCHAR)HalpPciConfigData) + 1), *Buffer); + ++Buffer; + if (Length == 2) + WRITE_REGISTER_UCHAR ((PULONG) (((PUCHAR)HalpPciConfigData) + 2), *Buffer); + if (Length == 3) + WRITE_REGISTER_USHORT ((PULONG) (((PUCHAR)HalpPciConfigData) + 2), *(PUSHORT)Buffer); + + break; + + case 2: + + if (Length < 2) { + WRITE_REGISTER_UCHAR ((PULONG) (((PUCHAR)HalpPciConfigData) + 2), *Buffer); + } else { + WRITE_REGISTER_USHORT ((PULONG) (((PUCHAR)HalpPciConfigData) + 2), *(PUSHORT)Buffer); + } + break; + + case 3: + + WRITE_REGISTER_UCHAR ((PULONG) (((PUCHAR)HalpPciConfigData) + 1), *Buffer); + break; + } + +} + + + + + +/*++ + +Routine Description: + + Partial read in the PCI config space ( less than one ULONG) + +Arguments: + + + + +Return Value: + + +--*/ +BOOLEAN +HalpPCIConfigPartialRead( + IN ULONG Offset, + IN ULONG Length, + IN PUCHAR Buffer + ) +{ + switch(Offset) { + + case 0: + + if (Length > 1) { + * (PUSHORT) Buffer = READ_REGISTER_USHORT ((PULONG) HalpPciConfigData); + if (* (PUSHORT) Buffer == 0XFFFF) return FALSE; + Buffer +=2; Offset+=2; + } + if (Length !=2) { + * Buffer = READ_REGISTER_UCHAR ((PULONG) (((PUCHAR)HalpPciConfigData) + Offset)); + if (* Buffer == 0XFF) return FALSE; + } + break; + + case 1: + + * Buffer = READ_REGISTER_UCHAR ((PULONG) (((PUCHAR)HalpPciConfigData) + 1)); + if (* Buffer == 0XFF) return FALSE; + ++Buffer; + if (Length == 2) { + * Buffer = READ_REGISTER_UCHAR ((PULONG) (((PUCHAR)HalpPciConfigData) + 2)); + if (* Buffer == 0XFF) return FALSE; + } else { + if (Length == 3) { + * (PUSHORT) Buffer = READ_REGISTER_USHORT ((PULONG) (((PUCHAR)HalpPciConfigData) + 2)); + if (* (PUSHORT) Buffer == 0XFFFF) return FALSE; + } + } + break; + + case 2: + + if (Length < 2) { + * Buffer = READ_REGISTER_UCHAR ((PULONG) (((PUCHAR)HalpPciConfigData) + 2)); + if (* Buffer == 0XFF) return FALSE; + } else { + * (PUSHORT) Buffer = READ_REGISTER_USHORT ((PULONG) (((PUCHAR)HalpPciConfigData) + 2)); + if (* (PUSHORT) Buffer == 0XFFFF) return FALSE; + } + break; + + case 3: + + * Buffer = READ_REGISTER_UCHAR ((PULONG) (((PUCHAR)HalpPciConfigData) + 1)); ++Buffer; + if (* Buffer == 0XFF) return FALSE; + break; + } + + return TRUE ; +} + + + +/*++ + +Routine Description: + + + +Arguments: + + + + +Return Value: + + +--*/ + +PCI_CONFIGURATION_TYPES +HalpPCIConfigCycleType ( + IN ULONG BusNumber, + IN PCI_SLOT_NUMBER Slot + ) + +{ + + // + // Determine if Type0, Type1, or Invalid + // + + if (BusNumber < 0 || BusNumber > (PCIMaxBuses - 1)) { + return PciConfigTypeInvalid; + } else if (BusNumber) { + return PciConfigType1; + } else { + return PciConfigType0; + } + +} + +/*++ + +Routine Description: + + + Update interrupt line : the read value in the PCI config space is form 0 to 6. + Each device needs a unique system interrupt number. This number is given by + this routine. The array HalpInterruptLine keeps the given system value. + + + +Arguments: + + + + +Return Value: + + +--*/ + +VOID +HalpIntLineUpdate( + IN ULONG BusNumber, + IN ULONG Slot, + PPCI_COMMON_CONFIG PciData + ) + +{ + + if (HalpInterruptLine[BusNumber][Slot] == 0) { + + switch (PciData->u.type0.InterruptLine) { + case 1: + if (HalpIntAMax > INTA_VECTOR + 50) { + DebugPrint(("More than 50 PCI Devices connected to INTA\n")); +#if DBG + DbgBreakPoint(); +#endif + } + + HalpInterruptLine[BusNumber][Slot] = HalpIntAMax; + ++ HalpIntAMax; + break; + case 2: + if (HalpIntBMax > INTB_VECTOR + 50) { + DebugPrint(("More than 50 PCI Devices connected to INTB\n")); +#if DBG + DbgBreakPoint(); +#endif + } + HalpInterruptLine[BusNumber][Slot] = HalpIntBMax; + ++ HalpIntBMax; + break; + case 3: + if (HalpIntCMax > INTC_VECTOR + 50) { + DebugPrint(("More than 50 PCI Devices connected to INTC\n")); +#if DBG + DbgBreakPoint(); +#endif + } + HalpInterruptLine[BusNumber][Slot] = HalpIntCMax; + ++ HalpIntCMax; + break; + case 4: + if (HalpIntDMax > INTD_VECTOR + 50) { + DebugPrint(("More than 50 PCI Devices connected to INTD\n")); +#if DBG + DbgBreakPoint(); +#endif + } + HalpInterruptLine[BusNumber][Slot] = HalpIntDMax; + ++ HalpIntDMax; + break; + case 5: + HalpInterruptLine[BusNumber][Slot] = SCSI_VECTOR; + break; + case 6: + HalpInterruptLine[BusNumber][Slot] = NET_LEVEL; + break; + } + + } + + PciData->u.type0.InterruptLine = HalpInterruptLine[BusNumber][Slot]; + +} + +BOOLEAN HalpTowerTestConf( + IN ULONG BusNumber, + IN PCI_SLOT_NUMBER Slot +) + +/*++ + +Routine Description + + Only for tower. + An access to an empty slot will do an exception if we don't care. + +Arguments + + None + +Return value + + True : slot ok + False : slot not ok + +++*/ + +{ +ULONG PciData,Buffer,SaveReg; +PCI_CONFIG_ADDR PciConfigAddrData; + + if (!HalpIsTowerPci) return TRUE; + + + PciData = PCI_TOWER_INTERRUPT_OFFSET | 0x80000000; + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciData)); + + // Save PCI interrupt register + SaveReg = READ_REGISTER_ULONG ((PULONG) HalpPciConfigData); + + // reset MAUI PCI error, set flag for exception routine + PciData = PI_RESET ; + WRITE_REGISTER_ULONG ((PULONG) HalpPciConfigData, *((PULONG) &PciData)); + + // write to vendor-id (ro) to see if exception appears. + PciConfigAddrData.Type = (BusNumber ? PciConfigType1 : PciConfigType0); + PciConfigAddrData.BusNumber = BusNumber; + PciConfigAddrData.DeviceNumber = Slot.u.bits.DeviceNumber; + PciConfigAddrData.FunctionNumber = 0; + PciConfigAddrData.Reserved = 0; + PciConfigAddrData.Enable = 1; + PciConfigAddrData.RegisterNumber = 0; // ULONG frontier + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciConfigAddrData)); + + PciData = 0xffffffff; + WRITE_REGISTER_ULONG ((PULONG) HalpPciConfigData, *((PULONG) &PciData)); + + // read MAUI PCI error + PciData = PCI_TOWER_INTERRUPT_OFFSET | 0x80000000; + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciData)); + Buffer = READ_REGISTER_ULONG ((PULONG) HalpPciConfigData); + + if ( Buffer & PI_CPU_PCI_TIMO) { + // reset MAUI PCI error, set flag for exception routine + PciData = PCI_TOWER_INTERRUPT_OFFSET | 0x80000000; + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciData)); + + PciData = PI_RESET ; + WRITE_REGISTER_ULONG ((PULONG) HalpPciConfigData, *((PULONG) &PciData)); + + // restore PCI interrupt + PciData = SaveReg; + WRITE_REGISTER_ULONG ((PULONG) HalpPciConfigData, *((PULONG) &PciData)); + + return FALSE; + } else { + // restore PCI interrupt + PciData = SaveReg; + WRITE_REGISTER_ULONG ((PULONG) HalpPciConfigData, *((PULONG) &PciData)); + return TRUE; + } +} + + + +/*++ + +Routine Description: + + Reads the targeted device to determine it's required resources. + Calls IoAssignResources to allocate them. + Sets the targeted device with it's assigned resoruces + and returns the assignments to the caller. + +Arguments: + +Return Value: + + STATUS_SUCCESS or error + +--*/ + +NTSTATUS +HalpAssignPCISlotResources ( + IN ULONG BusNumber, + IN PUNICODE_STRING RegistryPath, + IN PUNICODE_STRING DriverClassName OPTIONAL, + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT DeviceObject OPTIONAL, + IN ULONG Slot, + IN OUT PCM_RESOURCE_LIST *pAllocatedResources + ) + +{ + + NTSTATUS status; + PUCHAR WorkingPool; + PPCI_COMMON_CONFIG PciData; + PCI_SLOT_NUMBER PciSlot; + PCM_RESOURCE_LIST CmRes; + PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor; + ULONG i, j, length, memtype, BaseAd, BaseAd2, Offset; + ULONG BaseAddresses[10]; + ULONG cnt, len; + BOOLEAN conflict; + + *pAllocatedResources = NULL; + PciSlot = *((PPCI_SLOT_NUMBER) &Slot); + + // + // Allocate some pool for working space + // + + i = sizeof (CM_RESOURCE_LIST) + + sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR) * (PCI_TYPE0_ADDRESSES + 2) + + PCI_COMMON_HDR_LENGTH * 2; + + WorkingPool = (PUCHAR) ExAllocatePool (PagedPool, i); + + if (!WorkingPool) { + + return STATUS_NO_MEMORY; + } + + // + // Zero initialize pool, and get pointers into memory + // + + RtlZeroMemory (WorkingPool, i); + CmRes = (PCM_RESOURCE_LIST) WorkingPool; + PciData = (PPCI_COMMON_CONFIG) (WorkingPool + i - PCI_COMMON_HDR_LENGTH ); + + // + // Read the PCI device's configuration + // + + HalpReadPCIConfig (BusNumber, PciSlot, (PUCHAR) PciData, 0, PCI_COMMON_HDR_LENGTH); + + if (PciData->VendorID == PCI_INVALID_VENDORID || PciData->VendorID == 0x00) { + + ExFreePool (WorkingPool); + return STATUS_NO_SUCH_DEVICE; + + } + + // + // Update interrupt line + // + + HalpIntLineUpdate(BusNumber, Slot, PciData); + + // + // Build an CM_RESOURCE_LIST for the PCI device to report resources + // to IoReportResourceUsage. + // + // This code does *not* use IoAssignResources, as the PCI + // address space resources have been previously assigned by the ARC firmware + // + + CmRes->Count = 1; + CmRes->List[0].InterfaceType = PCIBus; + CmRes->List[0].BusNumber = BusNumber; + + CmRes->List[0].PartialResourceList.Count = 0; + + // + // Set current CM_RESOURCE_LIST version and revision + // + + CmRes->List[0].PartialResourceList.Version = 0; + CmRes->List[0].PartialResourceList.Revision = 0; + + CmDescriptor = CmRes->List[0].PartialResourceList.PartialDescriptors; + + // + // If PCI device has an interrupt resource, add it + // + + if (PciData->u.type0.InterruptPin) { + + CmDescriptor->Type = CmResourceTypeInterrupt; + CmDescriptor->ShareDisposition = CmResourceShareShared; + CmDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; + + CmDescriptor->u.Interrupt.Level = PciData->u.type0.InterruptLine; + CmDescriptor->u.Interrupt.Vector = PciData->u.type0.InterruptLine; + + CmRes->List[0].PartialResourceList.Count++; + CmDescriptor++; + + } + + // + // Add a memory/port resource for each PCI resource + // + + Offset = FIELD_OFFSET(PCI_COMMON_CONFIG,u.type0.BaseAddresses[0]); + + for (j=0; j < PCI_TYPE0_ADDRESSES; j++,Offset += sizeof(LONG)) { + +// +// Pb concerning especially SCSI : skip IO address when = 3bf0000 +// + + if ( (((ULONG)(PciData->u.type0.BaseAddresses[j]) & ~0x3) | 0x01) != 0x3bf0001 ) { + + BaseAddresses[j] = 0xFFFFFFFF; + + HalpWritePCIConfig (BusNumber, PciSlot,(PUCHAR)(&(BaseAddresses[j])), Offset, sizeof(LONG)); + HalpReadPCIConfig (BusNumber, PciSlot, (PUCHAR)(&(BaseAddresses[j])), Offset, sizeof(LONG)); + + + BaseAd = BaseAddresses[j]; + + if (BaseAd) { + + // + // calculate the length necessary - + // memory : the four less significant bits are only indicators + // IO : the two less significant bits are indicators + // + + length = 1 << ( BaseAd & PCI_ADDRESS_IO_SPACE ? 2 : 4); // mask the indicator bits + + while ( !( BaseAd & length ) && length ) { + length <<= 1; + } + + // now length => less significant bit set to 1. + + // scan for the most significant bit set to 1 + + if (BaseAd & PCI_ADDRESS_IO_SPACE) { + + memtype = 0; + BaseAd2 = (ULONG)(PciData->u.type0.BaseAddresses[j]) & ~0x3; +// BaseAd2 |= PCI_IO_BASE; + + CmDescriptor->Type = CmResourceTypePort; + CmDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + CmDescriptor->Flags = CM_RESOURCE_PORT_IO; + + CmDescriptor->u.Port.Length = length; + CmDescriptor->u.Port.Start.LowPart = BaseAd2; + + } else { + + memtype = BaseAd & PCI_ADDRESS_MEMORY_TYPE_MASK; + BaseAd2 = (ULONG)(PciData->u.type0.BaseAddresses[j]) & ~0xf; + + CmDescriptor->Type = CmResourceTypeMemory; + CmDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + CmDescriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE; + + CmDescriptor->u.Memory.Length = length; + CmDescriptor->u.Memory.Start.LowPart = BaseAd2; + } + + CmRes->List[0].PartialResourceList.Count++; + CmDescriptor++; + + HalpWritePCIConfig (BusNumber, PciSlot, (PUCHAR)(&(PciData->u.type0.BaseAddresses[j])), Offset, sizeof(ULONG)); + + } + } else { + + DebugPrint(("HalAssignResources : skip 0x3bf0001\n")); + } + } + + + // + // Setup the resource list. + // Count only the acquired resources. + // + + *pAllocatedResources = CmRes; + cnt = CmRes->List[0].PartialResourceList.Count; + len = sizeof (CM_RESOURCE_LIST) + + cnt * sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR); + +#if DBG + DbgPrint("HalAssignSlotResources: Acq. Resourses = %d (len %x list %x\n)", + cnt, len, *pAllocatedResources); +#endif + + // + // Report the IO resource assignments + // + + if (!DeviceObject) { + status = IoReportResourceUsage ( + DriverClassName, + DriverObject, // DriverObject + *pAllocatedResources, // DriverList + len, // DriverListSize + DeviceObject, // DeviceObject + NULL, // DeviceList + 0, // DeviceListSize + FALSE, // override conflict + &conflict // conflicted detected + ); + } else { + status = IoReportResourceUsage ( + DriverClassName, + DriverObject, // DriverObject + NULL, // DriverList + 0, // DriverListSize + DeviceObject, + *pAllocatedResources, // DeviceList + len, // DeviceListSize + FALSE, // override conflict + &conflict // conflicted detected + ); + } + + if (NT_SUCCESS(status) && conflict) { + + // + // IopReportResourceUsage saw a conflict? + // + +#if DBG + DbgPrint("HalAssignSlotResources: IoAssignResources detected a conflict: %x\n", + status); +#endif + status = STATUS_CONFLICTING_ADDRESSES; + + if (!DeviceObject) { + status = IoReportResourceUsage ( + DriverClassName, + DriverObject, // DriverObject + (PCM_RESOURCE_LIST) &i, // DriverList + sizeof (i), // DriverListSize + DeviceObject, + NULL, // DeviceList + 0, // DeviceListSize + FALSE, // override conflict + &conflict // conflicted detected + ); + } else { + status = IoReportResourceUsage ( + DriverClassName, + DriverObject, // DriverObject + NULL, // DriverList + 0, // DriverListSize + DeviceObject, + (PCM_RESOURCE_LIST) &i, // DeviceList + sizeof (i), // DeviceListSize + FALSE, // override conflict + &conflict // conflicted detected + ); + } + + ExFreePool (*pAllocatedResources); + *pAllocatedResources = NULL; + } + + if (!NT_SUCCESS(status)) { +#if DBG + DbgPrint("HalAssignSlotResources: IoAssignResources failed: %x\n", status); +#endif + if (!DeviceObject) { + status = IoReportResourceUsage ( + DriverClassName, + DriverObject, // DriverObject + (PCM_RESOURCE_LIST) &i, // DriverList + sizeof (i), // DriverListSize + DeviceObject, + NULL, // DeviceList + 0, // DeviceListSize + FALSE, // override conflict + &conflict // conflicted detected + ); + } else { + status = IoReportResourceUsage ( + DriverClassName, + DriverObject, // DriverObject + NULL, // DriverList + 0, // DriverListSize + DeviceObject, + (PCM_RESOURCE_LIST) &i, // DeviceList + sizeof (i), // DeviceListSize + FALSE, // override conflict + &conflict // conflicted detected + ); + } + + ExFreePool (*pAllocatedResources); + *pAllocatedResources = NULL; + } + +// ExFreePool (WorkingPool); + + return status; + +} + + +/*++ + +Routine Description: + +Arguments: + +Return Value: + + +--*/ + +NTSTATUS +HalpAdjustPCIResourceList ( + IN ULONG BusNumber, + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList + ) +{ + UCHAR buffer[PCI_COMMON_HDR_LENGTH]; + PCI_SLOT_NUMBER PciSlot; + PPCI_COMMON_CONFIG PciData; + LARGE_INTEGER liIo, liMem; + PIO_RESOURCE_REQUIREMENTS_LIST CompleteList; + PIO_RESOURCE_LIST ResourceList; + PIO_RESOURCE_DESCRIPTOR Descriptor; + ULONG alt, cnt; + + return STATUS_SUCCESS; + + liIo = RtlConvertUlongToLargeInteger (PCI_MAX_IO_ADDRESS); + liMem = RtlConvertUlongToLargeInteger (PCI_MAX_MEMORY_ADDRESS); + + // + // First, shrink to limits + // + + HalpAdjustResourceListUpperLimits (pResourceList, + liIo, // IO Maximum Address + liMem, // Memory Maximum Address + PCI_MAX_INTERRUPT_VECTOR, // irq + 0xffff); // dma + + // + // Fix any requested IRQs for this device to be the + // support value for this device. + // + + PciSlot = *((PPCI_SLOT_NUMBER) &(*pResourceList)->SlotNumber), + PciData = (PPCI_COMMON_CONFIG) buffer; + HalGetBusData ( PCIConfiguration, + BusNumber, + PciSlot.u.AsULONG, + PciData, + PCI_COMMON_HDR_LENGTH); + + if (PciData->VendorID == PCI_INVALID_VENDORID || PCI_CONFIG_TYPE (PciData) != 0) { + + return STATUS_UNSUCCESSFUL; + } + + + CompleteList = *pResourceList; + ResourceList = CompleteList->List; + + for (alt=0; alt < CompleteList->AlternativeLists; alt++) { + + Descriptor = ResourceList->Descriptors; + for (cnt = ResourceList->Count; cnt; cnt--) { + + switch (Descriptor->Type) { + + case CmResourceTypeInterrupt: + + // + // Interrupt lines on a PCI device can not move. + // Make sure the request fits within the PCI device's + // requirements. + // + + if (Descriptor->u.Interrupt.MinimumVector > PciData->u.type0.InterruptLine || + Descriptor->u.Interrupt.MaximumVector < PciData->u.type0.InterruptLine) { + + // + // descriptor doesn't fit requirements + // + + return STATUS_UNSUCCESSFUL; + + } + + // + // Fix the interrupt at the HAL programed routing + // + + Descriptor->u.Interrupt.MinimumVector = PciData->u.type0.InterruptLine; + Descriptor->u.Interrupt.MaximumVector = PciData->u.type0.InterruptLine; + break; + + case CmResourceTypePort: + break; + + case CmResourceTypeMemory: + + // + // Check for prefetchable memory + // + + if ( Descriptor->Flags & CM_RESOURCE_MEMORY_PREFETCHABLE) + { + // Set upper limit to max dense space address + + Descriptor->u.Memory.MinimumAddress.HighPart = 0; + Descriptor->u.Memory.MinimumAddress.LowPart = + PCI_MIN_DENSE_MEMORY_ADDRESS; + + Descriptor->u.Memory.MaximumAddress.HighPart = 0; + Descriptor->u.Memory.MaximumAddress.LowPart = + PCI_MAX_DENSE_MEMORY_ADDRESS; + } + + break; + + default: + return STATUS_UNSUCCESSFUL; + } + + // + // Next descriptor + // + + Descriptor++; + + } + + // + // Next Resource List + // + + ResourceList = (PIO_RESOURCE_LIST) Descriptor; + + } + + return STATUS_SUCCESS; +} + + +/*++ + +Routine Description: + + +--*/ + +VOID +HalpAdjustResourceListUpperLimits ( + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList, + IN LARGE_INTEGER MaximumPortAddress, + IN LARGE_INTEGER MaximumMemoryAddress, + IN ULONG MaximumInterruptVector, + IN ULONG MaximumDmaChannel + ) +{ + PIO_RESOURCE_REQUIREMENTS_LIST CompleteList; + PIO_RESOURCE_LIST ResourceList; + PIO_RESOURCE_DESCRIPTOR Descriptor; + ULONG alt, cnt; + + + // + // Walk each ResourceList and shrink any values to system limits + // + + CompleteList = *pResourceList; + ResourceList = CompleteList->List; + + for (alt=0; alt < CompleteList->AlternativeLists; alt++) { + + Descriptor = ResourceList->Descriptors; + for (cnt = ResourceList->Count; cnt; cnt--) { + + + // + // Make sure descriptor limits fall within the + // CompleteList->InterfaceType & CompleteList->BusNumber. + // + // + + switch (Descriptor->Type) { + + case CmResourceTypePort: + + if (Descriptor->u.Port.MaximumAddress.QuadPart > + MaximumPortAddress.QuadPart) { + + Descriptor->u.Port.MaximumAddress = MaximumPortAddress; + } + break; + + case CmResourceTypeInterrupt: + + if (Descriptor->u.Interrupt.MaximumVector > MaximumInterruptVector ) { + + Descriptor->u.Interrupt.MaximumVector = MaximumInterruptVector; + } + break; + + case CmResourceTypeMemory: + + if (Descriptor->u.Memory.MaximumAddress.QuadPart > + MaximumMemoryAddress.QuadPart) { + + Descriptor->u.Memory.MaximumAddress = MaximumMemoryAddress; + } + break; + + case CmResourceTypeDma: + if (Descriptor->u.Dma.MaximumChannel > MaximumDmaChannel ) { + + Descriptor->u.Dma.MaximumChannel = MaximumDmaChannel; + } + break; + + } + + // + // Next descriptor + // + + Descriptor++; + + } + + // + // Next Resource List + // + + ResourceList = (PIO_RESOURCE_LIST) Descriptor; + + } + +} + + diff --git a/private/ntos/nthals/halsnip/mips/snipbus.h b/private/ntos/nthals/halsnip/mips/snipbus.h new file mode 100644 index 000000000..f1ba64346 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/snipbus.h @@ -0,0 +1,104 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/snipbus.h,v 1.2 1995/11/02 11:04:33 flo Exp $") +/*+++ + +Copyright (c) 1993-1994 Siemens Nixdorf Informationssysteme AG + +Module Name: + + PCIdef.h + +Abstract: + + Hal specific PCI bus structures */ + + +#define PCI_MAX_LOCAL_DEVICE 32 +#define PCI_MAX_BUS_NUMBER 250 +#define PCI_MAX_IO_ADDRESS 0x1FFFFFFF +#define PCI_MAX_MEMORY_ADDRESS 0x1FFFFFFF +#define PCI_MAX_SPARSE_MEMORY_ADDRESS PCI_MAX_MEMORY_ADDRESS +#define PCI_MIN_DENSE_MEMORY_ADDRESS PCI_MEMORY_PHYSICAL_BASE +#define PCI_MAX_DENSE_MEMORY_ADDRESS PCI_MAX_MEMORY_ADDRESS +#define PCI_MAX_INTERRUPT_VECTOR 0x100 + +#define PCI_CONFIG_TYPE(PciData) ((PciData)->HeaderType & ~PCI_MULTIFUNCTION) + +// +// Define PciConfigAddr register structure +// +typedef struct _PCI_CONFIG_ADDR { + ULONG Type : 2; + ULONG RegisterNumber : 6; + ULONG FunctionNumber : 3; + ULONG DeviceNumber : 5; + ULONG BusNumber : 8; + ULONG Reserved : 7; + ULONG Enable : 1; +} PCI_CONFIG_ADDR, *PPCI_CONFIG_ADDR; + +// +// Define PCI configuration cycle types. +// +typedef enum _PCI_CONFIGURATION_TYPES { + PciConfigTypeInvalid = -1, + PciConfigType0 = 0, + PciConfigType1 = 1 +} PCI_CONFIGURATION_TYPES, *PPCI_CONFIGURATION_TYPES; + +// +// Define PCI cycle/command types. +// + +typedef enum _PCI_COMMAND_TYPES{ + PciCommandInterruptAcknowledge = 0x0, + PciCommandSpecialCycle = 0x1, + PciCommandIoRead = 0x2, + PciCommandIoWrite = 0x3, + PciCommandMemoryRead = 0x6, + PciCommandMemoryWrite = 0x7, + PciCommandConfigurationRead = 0xa, + PciCommandConfigurationWrite = 0xb, + PciCommandMemoryReadMultiple = 0xc, + PciCommandDualAddressCycle = 0xd, + PciCommandMemoryReadLine = 0xe, + PciCommandMemoryWriteAndInvalidate = 0xf, + MaximumPciCommand +} PCI_COMMAND_TYPES, *PPCI_COMMAND_TYPES; + + +// +// PCI platform-specific functions +// + +VOID +HalpInitializePCIBus ( + VOID + ); + +VOID +HalpAdjustResourceListUpperLimits ( + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList, + IN LARGE_INTEGER MaximumPortAddress, + IN LARGE_INTEGER MaximumMemoryAddress, + IN ULONG MaximumInterruptVector, + IN ULONG MaximumDmaChannel + ); + +NTSTATUS +HalpAdjustPCIResourceList ( + IN ULONG BusNumber, + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList + ); + +NTSTATUS +HalpAdjustEisaResourceList ( + IN ULONG BusNumber, + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList + ); + +NTSTATUS +HalpAdjustIsaResourceList ( + IN ULONG BusNumber, + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList + ); + diff --git a/private/ntos/nthals/halsnip/mips/snipci.h b/private/ntos/nthals/halsnip/mips/snipci.h new file mode 100644 index 000000000..0a4651ebe --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/snipci.h @@ -0,0 +1,366 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/snipci.h,v 1.6 1996/02/23 17:55:12 pierre Exp $") +/*+++ + +Copyright (c) 1993-1994 Siemens Nixdorf Informationssysteme AG + +Module Name: + + PCIdef.h + +Abstract: + + This file describes hardware addresses + for SNI PCI machines. + + + +---*/ + +#ifndef _PCIDEF_ +#define _PCIDEF_ + + +// --------------------- +// desktop and minitower - +// --------------------- + + +// +// define various masks for the interrupt sources register +// + +/* + The interrupt Source Register on a PCI minitower or desktop has the following bits: + + 7 6 5 4 3 2 1 0 + +-------------------------------+ + | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 Low Activ; 1 High activ; x not connected + +-------------------------------+ + |________ INT2 Interrupt (Push button, high temp, pci asic) + |____________ PCI_INTD + |________________ PCI_INTC + |____________________ PCI_INTB + |________________________ PCI_INTA + |____________________________ EISA_INT + |________________________________ SCSI_INT + |____________________________________ ETHERNET_INT + + + The second source for Interrupt Information is the MachineStatusRegister, which has the following bits: + + 7 6 5 4 3 2 1 0 + +-------------------------------+ + | x | 0 | 0 | 1 | x | 0 | 0 | 0 | 0 Low Activ; 1 High activ; x not connected + +-------------------------------+ + |________ Power Off Request (only RM200) + |____________ ASIC int + |________________ PushButton + |________________________ NMI + |____________________________ Power Management ie system wakeup (only rm200) + |________________________________ High Temperature +*/ + +#define PCI_INTERRUPT_MASK 0xdf +#define PCI_INT2_MASK 0x01 // push-button, high temp, asic... +#define PCI_INTD_MASK 0x02 +#define PCI_INTC_MASK 0x04 +#define PCI_INTB_MASK 0x08 +#define PCI_INTA_MASK 0x10 +#define PCI_EISA_MASK 0x20 +#define PCI_SCSI_MASK 0x40 +#define PCI_NET_MASK 0x80 + +#define PCI_MSR_MASK_D 0x67 +#define PCI_MSR_MASK_MT 0x46 +#define PCI_MSR_POFF_MASK 0x01 +#define PCI_MSR_ASIC_MASK 0x02 +#define PCI_MSR_PB_MASK 0x04 +#define PCI_MSR_NMI 0x10 // NMI from the EISA controller +#define PCI_MSR_TEMP_MASK 0x40 // OverTemperature Interrupt in the MSR (RM400MT only) (high active) +#define PCI_MSR_PMGNT_MASK 0x20 // power management (system wake-up) + +#define PCI_NVMEM_PHYSICAL_BASE 0x1ff00000 // physical base of nonvolatile RAM and RTC + +// +// SNI ASIC registers +// + +#define PCI_UCONF_REGISTER 0xbfff0000 +#define PCI_IOADTIMEOUT2_REGISTER 0xbfff0008 +#define PCI_IOMEMCONF_REGISTER 0xbfff0010 +#define PCI_IOMMU_REGISTER 0xbfff0018 +#define PCI_IOADTIMEOUT1_REGISTER 0xbfff0020 +#define PCI_DMAACCESS_REGISTER 0xbfff0028 +#define PCI_DMAHIT_REGISTER 0xbfff0030 +#define PCI_ERRSTATUS_REGISTER 0xbfff0038 +#define PCI_MEMSTAT_ECCERR (1<<0) +#define PCI_MEMSTAT_ECCSINGLE (1<<3) +#define PCI_MEMSTAT_PARERR (1<<4) +#define PCI_ERRADDR_REGISTER 0xbfff0040 +#define PCI_SYNDROME_REGISTER 0xbfff0048 +#define PCI_ITPEND_REGISTER 0xbfff0050 +#define PCI_ASIC_ECCERROR (1<<8) +#define PCI_ASIC_TRPERROR (1<<9) +#define PCI_ASIC_IOTIMEOUT (1<<7) +#define PCI_IRQSEL_REGISTER 0xbfff0058 +#define PCI_TESTMEM_REGISTER 0xbfff0060 +#define PCI_ECCREG_REGISTER 0xbfff0068 +#define PCI_CONF_ADDR_REGISTER 0xbfff0070 // (EISA_IO + 0xcf8) +#define PCI_ASIC_ID_REGISTER 0xbfff0078 // Read +#define PCI_SOFT_RESET_REGISTER 0xbfff0078 //Write +#define PCI_PIA_OE_REGISTER 0xbfff0080 +#define PCI_PIA_DATAOUT_REGISTER 0xbfff0088 +#define PCI_PIA_DATAIN_REGISTER 0xbfff0090 +#define PCI_CACHECONF_REGISTER 0xbfff0098 +#define PCI_INVSPACE_REGISTER 0xbfff00A0 +#define PCI_PCICONF_REGISTER 0xbfff0100 + +// +// System dependant registers +// + +#define PCI_MSR_PHYSICAL_ADDR 0x1fd00000 // machine status register +#define PCI_MSR_ADDR 0xbfd00000 // machine status register | KSEG1 +#define PCI_CSWITCH_PHYSICAL_ADDR 0x1fd10000 // DIP switch register +#define PCI_CSWITCH_ADDR 0xbfd10000 // DIP switch register | KSEG1 +#define PCI_INTERRUPT_SOURCE_PHYSICAL_BASE 0x1fd20000 // physical base of interrupt source register +#define PCI_INTERRUPT_SOURCE_REGISTER 0xbfd20000 // physical base | KSEG1_BASE +#define PCI_CLR_TMP_PHYSICAL_ADDR 0x1fd40000 // Clear Temperature Register +#define PCI_CLR_TMP_ADDR 0xbfd40000 // Clear Temperature Register | KSEG1 +#define PCI_MCR_PHYSICAL_ADDR 0x1fd80000 // MachineConfigRegister +#define PCI_MCR_ADDR 0xbfd80000 // MachineConfigRegister | KSEG1 +#define PCI_LED_PHYSICAL_ADDR 0x1fda0000 // LED Register physical +#define PCI_LED_ADDR 0xbfda0000 // LED Register | KSEG1_BASE +#define PCI_ISA_MAP_PHYSICAL_BASE 0x1fdb0000 // physical base of ISA map register (for BusMaster Devices) +#define PCI_ISA_MAP 0xbfdb0000 // physical base | KSEG1_BASE +#define PCI_CSRSTBP_PHYSICAL_ADDR 0x1fdc0000 // reset dbg button int +#define PCI_CSRSTBP_ADDR 0xbfdc0000 // reset dbg button int +#define PCI_CLRPOFF_PHYSICAL_ADDR 0x1fdd0000 // RM200 only +#define PCI_CLRPOFF_ADDR 0xbfdd0000 // RM200 only +#define PCI_PWDN_PHYSICAL_ADDR 0x1fdf0000 // RM200 only +#define PCI_PWDN_ADDR 0xbfdf0000 // RM200 only +#define PCI_MCR_SOFTRESET 0xdf // bit 6 set to zero +#define PCI_MCR_POWEROFF 0xfd // bit 2 set to zero + +// +// RealTimeClock Chip +// + +#define PCI_REAL_TIME_CLOCK_ADDRESS 0x14000070 // physical base of RTC +#define PCI_REAL_TIME_CLOCK 0xb4000070 // physical base of RTC | KSEG1_BASE + +#define RTC_ADDR_PCIMT PCI_REAL_TIME_CLOCK +#define RTC_DATA_PCIMT PCI_REAL_TIME_CLOCK + 1 + +// +// Standard PCI addresses +// + +#define PCI_IO_PHYSICAL_BASE 0x14000000 +#define PCI_IO_BASE 0xb4000000 +#define PCI_MEMORY_PHYSICAL_BASE 0x18000000 // memory area (cpu 0x18... chip 0x18...) +#define PCI_MEMORY_BELOW1M_PHYSICAL_BASE 0x10000000 // for memory below 1Mb (cpu 0x10... chip 0x00...) +#define PCI_MEMORY_BASE 0xb8000000 + +#define PCI_CONF_DATA_REGISTER (PCI_IO_BASE + 0xcfc) + +#define PCI_IOMEMCONF_ENIOTMOUT (1 <<21 ) +#define PCI_IOMEMCONF_FORCE_ECC (1 <<29 ) +#define PCI_IOMEMCONF_ENCHKECC (1 <<30 ) + +#define PCI_ECCTEST_REGISTER (1 <<30 ) + +// def for PCI_MSR_REGISTER + +#define PCI_MSR_REV_ASIC (1 <<3 ) + +// def for PCI_IRQSEL_REGISTER + +#define PCI_IRQSEL_MASK 0x380 // enable IOTIMEOUT ECCERROR TRPERROR +#define PCI_IRQSEL_TIMEOUTMASK 0x80 // enable IOTIMEOUT +#define PCI_IRQSEL_INT 0x803ff // Int line = 0 for IOTIMOUT, ECCERROR and TRPERROR + +// +// RM300 extra timer (on board) +// + +#define PCI_EXTRA_TIMER_PHYSICAL_ADDR 0x1fde0000 // Timer for system clock +#define PCI_EXTRA_TIMER_ADDR 0xbfde0000 // Timer for system clock | KSEG1_BASE +#define PCI_EXTRA_TIMER_ACK_ADDR 0xbfd90000 // reset extra Timer Interrupt | KSEG1_BASE + +// +// Definitions for 82374 Bridge PCI_EISA +// + +#define PCI_ESC_ADDR 0xb4000022 +#define PCI_ESC_DATA 0xb4000023 +#define PCI_ESC_ID_82374 0x2 +#define PCI_REV_ID_82374 0x8 + +#define REV_ID_82374_SB 0x3 + + +// ------------------------- +// definitions for PCI Tower - +// ------------------------- + + + +#define PCI_TOWER_CONF_ADDR_REGISTER (PCI_IO_BASE + 0xcf8) +#define PCI_TOWER_LED_ADDR PCI_TOWER_CPU_STATUS +#define PCI_TOWER_LED_MASK 0xFFFCFFFC + +// +// MAUI MP_BUS Configuration/Status +// + +#define PCI_TOWER_MP_BUS_CONFIG 0xbfff0000 + +#define PCI_TOWER_GEN_INTERRUPT 0xbfff0008 +#define PCI_TOWER_INTERRUPT_SOURCE_REGISTER PCI_TOWER_GEN_INTERRUPT + +// define various mask for interrupt + + +#define PCI_TOWER_EISA_MASK 0x00400000 +#define PCI_TOWER_SCSI1_MASK 0x00100000 +#define PCI_TOWER_SCSI2_MASK 0x00200000 +#define PCI_TOWER_INTA_MASK 0x00010000 +#define PCI_TOWER_INTB_MASK 0x00020000 +#define PCI_TOWER_INTC_MASK 0x00040000 +#define PCI_TOWER_INTD_MASK 0x00080000 +#define PCI_TOWER_MP_BUS_MASK 0x00000003 +#define PCI_TOWER_C_PARITY_MASK 0x00000001 +#define PCI_TOWER_C_REGSIZE 0x00000002 +#define PCI_TOWER_M_ECC_MASK 0x00000004 +#define PCI_TOWER_M_ADDR_MASK 0x00000008 +#define PCI_TOWER_M_SLT_MASK 0x00000010 +#define PCI_TOWER_M_CFG_MASK 0x00000020 +#define PCI_TOWER_M_RC_MASK 0x00000040 +#define PCI_TOWER_D_INDICATE_MASK 0x00000080 +#define PCI_TOWER_D_ERROR_MASK 0x00000100 +#define PCI_TOWER_P_ERROR_MASK 0x00000200 + +#define PCI_TOWER_MP_BUS_ERROR_STATUS 0xbfff0010 +#define PCI_TOWER_MP_BUS_ERROR_ADDR 0xbfff0018 +#define PCI_TOWER_MP_BUS_PCI_LOCK 0xbfff0020 +#define MP_BUS_PCI_LOCK_REQ 0x2 +#define MP_BUS_PCI_LOCK_ACK 0x1 + +// +// MAUI Memory Configuration registers +// + +#define PCI_TOWER_MEM_SLOT_0 0xbfff1000 +#define PCI_TOWER_MEM_SLOT_1 0xbfff1008 +#define PCI_TOWER_MEM_SLOT_2 0xbfff1010 +#define PCI_TOWER_MEM_SLOT_3 0xbfff1018 +#define PCI_TOWER_MEM_SLOT_4 0xbfff1020 +#define PCI_TOWER_MEM_SLOT_5 0xbfff1028 +#define PCI_TOWER_MEM_SLOT_6 0xbfff1030 +#define PCI_TOWER_MEM_SLOT_7 0xbfff1038 + +#define PCI_TOWER_MEM_CONTROL_0 0xbfff1040 + +#define ERROR_COUNTER_MASK 0xff000000 +#define ERROR_COUNTER_INITVALUE 0xff0000 // to get overflow with ffff errors +#define PCI_TOWER_MEM_CONTROL_1 0xbfff1048 +#define PCI_TOWER_MEM_CONTROL_2 0xbfff1050 + +#define PCI_TOWER_MEM_CONFIG 0xbfff1058 +#define PCI_TOWER_MEM_ERROR_DATA_H 0xbfff1060 +#define PCI_TOWER_MEM_ERROR_DATA_L 0xbfff1068 +#define PCI_TOWER_MEM_ERROR_ECC 0xbfff1070 +#define PCI_TOWER_MEM_ERROR_ADDR 0xbfff1078 +#define MEM_ADDR_MASK 0xffffffe0 + +// PCI configuration register +#define PCI_TOWER_COMMAND_OFFSET 0x04 +#define PCI_TOWER_PM_LOCKSPACE 0x64 +#define PCI_TOWER_INTERRUPT_OFFSET 0x68 +#define PCI_TOWER_INITIATOR_ADDR_OFFSET 0x6c +#define PCI_TOWER_TARGET_ADDR_OFFSET 0x70 +#define PCI_TOWER_PAR_0_OFFSET 0x74 +#define PCI_TOWER_PAR_1_OFFSET 0x78 + +// definitions for command register + +#define EN_SERR 0x100 + +// definitions for PCI_interrupt register + +#define PI_RESET 0xff000000 // reset interrupt in PCI_Interrupt + +#define PI_INITF 0x80000000 // mask for first Initiator interrupt in PCI_Interrupt +#define PI_INITM 0x40000000 // mask for multi Initiator interrupt in PCI_Interrupt +#define PI_TARGF 0x20000000 // mask for first Target interrupt in PCI_Interrupt +#define PI_TARGM 0x10000000 // mask for multi Target interrupt in PCI_Interrupt +#define PI_PARF 0x08000000 // mask for first Parity interrupt in PCI_Interrupt +#define PI_PARM 0x04000000 // mask for multi Parity interrupt in PCI_Interrupt + + +// Cause for initiator interrupts +#define PI_READ_PCI 0x00200000 // from PCI +#define PI_CPU_PCI_TIMO 0x00100000 // CPU to PCI timeout +#define PI_CPU_PCI_ADDR 0x00080000 // address error +#define PI_CPU_PCI_PAR 0x00020000 // initiator receives target abort +#define PI_REC_TARGET_RETRY 0x00010000 // initiator receives target retry +#define PI_REC_TARGET_DISCON 0x00008000 // initiator receives target disconnect +// Cause for target interrupts +#define PI_TARGET_MEM 0x00000080 // read error from memory +#define PI_TARGET_RETRY 0x00000040 // target acts retry +#define PI_TARGET_ADDR_PAR 0X00000020 // PCI_to_MEM addr parity +#define PI_TARGET_DATA_PAR 0x00000010 // PCI_to_MEM data patity +// enable interrupts +#define EN_INIT_INT 0x00800000 // enable initiator interrupt +#define EN_INIT_INTR 0x00400000 // enable initiator receives target disconnect +#define EN_TARG_INTR 0x00000001 // enable target interrupt +#define MASK_INT 0x00c00001 +// +// DCU interface registers +// + +#define PCI_TOWER_CONTROL 0xbfff2000 + +#define PCI_TOWER_INDICATE 0xbfff2008 + +// sources for DCU interrupt + +#define PCI_TOWER_DI_PB_MASK 0x00000100 +#define PCI_TOWER_DI_EISA_NMI 0x00000080 +#define PCI_TOWER_DI_AC_FAIL 0x00000004 +#define PCI_TOWER_DI_FAN_FAIL 0x00000008 +#define PCI_TOWER_DI_THERMO1_FAIL 0x00000010 +#define PCI_TOWER_DI_THERMO2_FAIL 0x00000020 +#define PCI_TOWER_DI_THERMO3_FAIL 0x00000040 +#define PCI_TOWER_DI_NT_FAN_FAIL 0x00000200 +#define PCI_TOWER_DI_SCSI1_TERM_FAIL 0x00000400 +#define PCI_TOWER_DI_SCSI2_INT_TERM_FAIL 0x00000800 +#define PCI_TOWER_DI_SCSI2_EXT_TERM_FAIL 0x00001000 +#define PCI_TOWER_DI_AUI_FAIL 0x00002000 +#define PCI_TOWER_DI_EXTRA_TIMER 0x00040000 + +#define PCI_TOWER_DCU_CONTROL 0xbfff2000 +#define PCI_TOWER_DCU_STATUS 0xbfff2010 +#define PCI_TOWER_CPU_STATUS 0xbfff2018 +#define PCI_TOWER_DCU_ERROR 0xbfff2020 + +// definitions for DCU error + +#define DE_CPU_ID 0x00006000 +#define DE_WRN 0x00001000 +#define DE_ADDR 0x00000fe0 +#define DE_ERR_ADDR 0x1fff2000 + +// definitions for additional timer + +#define PCI_TOWER_TIMER_CMD_REG 0xbff03ffb +#define PCI_TOWER_TIMER_COUNT_REG 0xbff03ffc +#define PCI_TOWER_TIMER_VALUE_REG 0xbff03ffd + +// definitions for DCU Control + +#define DC_SWRESET 0x04000000 +#define DC_POWEROFF 0x02000000 + +#endif // _PCIDEF_ diff --git a/private/ntos/nthals/halsnip/mips/sniregs.h b/private/ntos/nthals/halsnip/mips/sniregs.h new file mode 100644 index 000000000..6f50d42f0 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/sniregs.h @@ -0,0 +1,139 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/sniregs.h,v 1.1 1995/07/20 16:03:21 flo Exp $") +/*++ + +Copyright (c) 1993 SNI + +Module Name: + + SNIregs.h + +Abstract: + + This module is the header file that describes hardware structures + for the system board registers + The System addresses are found in SNIdef.h + +--*/ + +#ifndef _SNIREGS_ +#define _SNIREGS_ + + +/******************************************************************* +** Description of the R4x000 ASIC Chipset registers for SNI Machines +** +** 32 bits access only +*******************************************************************/ + +// +// UCONF register +// + +#define UCONF_ENSCMODE (1<<0) /* Secondary mode valid for R4000 */ +#define UCONF_ENEXTINT (1<<1) /* External interruption request */ +#define UCONF_NMI (1<<5) /* Interrupt level for NMI */ +#define UCONF_NMI_MSK (1<<6) /* Interrupt mask for NMI */ +#define UCONF_MDINT (1<<7) /* Select test mode for interruptions */ +#define UCONF_INT0_MSK (1<<8) /* Interrupt mask for INT0 ( eisa ) */ +#define UCONF_INT1_MSK (1<<9) /* Interrupt mask for INT1 ( scci 1, 2 ) */ +#define UCONF_INT2_MSK (1<<10) /* Interrupt mask for INT2 ( duart 2681 ) */ +#define UCONF_INT3_MSK (1<<11) /* Interrupt mask for INT3 ( timer 8254 ) */ +#define UCONF_INT4_MSK (1<<12) /* Interrupt mask for INT4 ( lance ) */ +#define UCONF_INT5_MSK (1<<13) /* Interrupt mask for INT5 ( dbg button ) */ +#define UCONF_INT0 (1<<14) /* Interrupt level for INT0 ( eisa ) */ +#define UCONF_INT1 (1<<15) /* Interrupt level for INT1 ( scci 1, 2 ) */ +#define UCONF_INT2 (1<<16) /* Interrupt level for INT2 ( duart 2681 ) */ +#define UCONF_INT3 (1<<17) /* Interrupt level for INT3 ( timer 8254 ) */ +#define UCONF_INT4 (1<<18) /* Interrupt level for INT4 ( lance ) */ +#define UCONF_INT5 (1<<19) /* Interrupt level for INT5 ( dbg button ) */ +#define UCONF_ENCPUHIT (1<<20) /* Enable address comparators */ +#define UCONF_ENCKDATA (1<<25) /* Enable check bits on data read */ +#define UCONF_SYSCMD0 (1<<26) +#define UCONF_SYSCMD1 (1<<27) +#define UCONF_SYSCMD2 (1<<28) +#define UCONF_SYSCMD3 (1<<29) + +#define UCONF_INT UCONF_INT4|UCONF_INT0 + +// +// IOADTIMEOUT2 & IOADTIMEOUT1 +// + +#define IO_HOLD (1<<0) /* The R4K_CS request the IO bus */ +#define IO_HLDA (1<<1) /* The IO arbitrer acknowledge */ +#define IO_HWR (1<<3) /* Set to 1 for a write IO cycle */ +#define IO_HADR_MASK 0x3FFFFFF8 /* IO address (29:3) in progress */ + +// +// IOMEMCONF +// + + +#define IOMEM_RAFPER 8 /* Select Refresh Period */ +#define IOMEM_SELRC (1<<4) /* Select fast Ttc time on memory */ +#define IOMEM_SELRAF (1<<5) /* Select fast refresh precharge */ +#define IOMEM_SELSIDE (1<<6) /* Select dual side SIPS */ +#define IOMEM_SELDD (1<<7) /* Select DD pattern for memory */ +#define IOMEM_SEL16MB (1<<8) /* Select 16 Mb technology SIPS */ +#define IOMEM_SELDHOLD (1<<9) /* Select long hold time on data write */ +#define IOMEM_DISHLDA (1<<15) /* Mask arbitrer acknowledge */ +#define IOMEM_ENRDCMP (1<<16) /* Enable anticipation on IO read */ +#define IOMEM_ENWRCMP (1<<20) /* Enable bufferisation on IO write */ +#define IOMEM_ENIOTMOUT (1<<21) /* Enable output timeout */ +#define IOMEM_SELIODD (1<<22) /* Enable fast mode for IO burst DD */ +#define IOMEM_MDTIMEOUT (1<<23) /* Select short timeout */ + +#define BANK_16 0 +#define BANK_32 IOMEM_SELSIDE +#define BANK_64 IOMEM_SEL16MB +#define BANK_128 IOMEM_SEL16MB | IOMEM_SELSIDE + +#define IOMEM_INIT IOMEM_RAFPER /* Initial register load */ + +// +// IOMMU +// + +#define IOMMU_SWAP 0x7fff /* all segments swapped */ +#define IOMMU_BITS 0x0000 /* all segments 32 bits */ + + +// +// DMACCESS & DMAHIT +// + +#define DMA_COUNT_MASK 0x0000FFFF /* Count mask (15:0) */ + + +// +// MACHINE STATUS REGISTER (MSR) +// + +/* SNI machine status register information */ + +#define MSR_VSYNC (1<<0) /* active high - video synchronization */ +#define MSR_TEMP (1<<1) /* active high - excessive temperature */ +#define MSR_LINEGOOD (1<<2) /* active low - power good */ +#define MSR_TIMER1 (1<<3) /* active low - int timer 1 */ +#define MSR_TIMER0 (1<<4) /* active low - int timer 0 */ +#define MSR_DBG_BUT (1<<5) /* active low - debug button int */ +#define MSR_TIMEOUT (1<<6) /* active low - timeout int */ +#define MSR_BAT_EN (1<<7) /* active high - batteries connected */ + +// +// MACHINE CONFIGURATION REGISTER (MCR) +// + +/* SNI machine configuration register */ + +#define MCR_TEMPBATACK (1<<0) /* active high - Disable / clear TEMP an Temp info */ +#define MCR_POWER_OFF (1<<1) /* active high - Stop power */ +#define MCR_STOP_BAT (1<<2) /* active high - Stop batteries */ +#define MCR_PODD (1<<3) /* active high - Select ODD parity R4K_CS */ +#define MCR_INRESET (1<<5) /* active high - Reset board */ +#define MCR_ENBREAK (1<<7) /* active high - Enable Break Duart B machine reset */ + + +#define LINEGOOD_L MSR_LINEGOOD /* high : powerfail */ + +#endif // _SNIREGS_ diff --git a/private/ntos/nthals/halsnip/mips/unicache.s b/private/ntos/nthals/halsnip/mips/unicache.s new file mode 100644 index 000000000..7be37c8ee --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/unicache.s @@ -0,0 +1,1155 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/unicache.s,v 1.2 1995/11/02 11:04:33 flo Exp $") +// TITLE("Cache Flush") +//++ +// +// Copyright (c) 1991-1993 Microsoft Corporation +// +// Module Name: +// +// unicache.s +// +// Abstract: +// +// This module implements the code necessary for cache operations on +// MIPS R4000 Uni Processor machine. +// +// Environment: +// +// Kernel mode only. +// +//-- + +#include "halmips.h" + +// +// Note: On the SNI machines all single processor machines are configured in the Firmware +// tree with the size of the Primary cache matching the physical size. +// So, even Orion CPU are configured with 16KB not 2 sets of 8Kb. +// In this case wqe can use the Routines special for Orion CPU also for +// R4400 CPU. +// + +#if!defined(ORION) +#define ORION +#endif + +// +// some bitmap defines to display cache activities via the LED's +// in the SNI RM machines +// + +#define SWEEP_DCACHE 0xc0 // 1100 0000 +#define FLUSH_DCACHE_PAGE 0x80 // 1000 0000 +#define PURGE_DCACHE_PAGE 0x40 // 0100 0000 + +#define SWEEP_ICACHE 0x30 // 0011 0000 +#define PURGE_ICACHE_PAGE 0x10 // 0001 0000 + +// +// Define cache operations constants. +// + +#define COLOR_BITS (7 << PAGE_SHIFT) // color bit (R4000 - 8kb cache) +#define COLOR_MASK (0x7fff) // color mask (R4000 - 8kb cache) +#define FLUSH_BASE 0xfffe0000 // flush base address +#define PROTECTION_BITS ((1 << ENTRYLO_V) | (1 << ENTRYLO_D) ) // + + SBTTL("Change Color Page") +//++ +// +// VOID +// HalChangeColorPage ( +// IN PVOID NewColor, +// IN PVOID OldColor, +// IN ULONG PageFrame +// ) +// +// Routine Description: +// +// This function changes the color of a page if the old and new colors +// do not match. +// +// The algorithm used to change colors for a page is as follows: +// +// 1. Purge (hit/invalidate) the page from the instruction cache +// using the old color. +// +// 2. Purge (hit/invalidate) the page from the data cache using +// the old color. +// +// Arguments: +// +// NewColor (a0) - Supplies the page aligned virtual address of the +// new color of the page to change. +// +// OldColor (a1) - Supplies the page aligned virtual address of the +// old color of the page to change. +// +// PageFrame (a2) - Supplies the page frame number of the page that +// is changed. +// +// Return Value: +// +// None. +// +//-- + + .struct 0 + .space 3 * 4 // fill +CpRa: .space 4 // saved return address +CpFrameLength: // length of stack frame +CpA0: .space 4 // (a0) +CpA1: .space 4 // (a1) +CpA2: .space 4 // (a2) +CpA3: .space 4 // (a3) + + NESTED_ENTRY(HalChangeColorPage, CpFrameLength, zero) + + subu sp,sp,CpFrameLength // allocate stack frame + sw ra,CpRa(sp) // save return address + + PROLOGUE_END + + and a0,a0,COLOR_BITS // isolate new color bits + and a1,a1,COLOR_BITS // isolate old color bits + beq a0,a1,10f // if eq, colors match + sw a1,CpA1(sp) // save old color bits + sw a2,CpA2(sp) // save page frame + +// +// Purge the instruction cache using the old page color. +// + + move a0,a1 // set color value + move a1,a2 // set page frame number + li a2,PAGE_SIZE // set length of purge + jal HalPurgeIcachePage // purge instruction cache page + +// +// Flush the data cache using the old page color. +// + + lw a0,CpA1(sp) // get old color bits + lw a1,CpA2(sp) // get page frame number + li a2,PAGE_SIZE // set length of purge + jal HalFlushDcachePage // purge data cache page +10: lw ra,CpRa(sp) // get return address + addu sp,sp,CpFrameLength // deallocate stack frame + j ra // return + + .end HalChangeColorPage + + SBTTL("Flush Data Cache Page") +//++ +// +// VOID +// HalpFlushDcachePageUni ( +// IN PVOID Color, +// IN ULONG PageFrame, +// IN ULONG Length +// ) +// +// Routine Description: +// +// This function flushes (hit/writeback/invalidate) up to a page of data +// from the data cache. +// +// Arguments: +// +// Color (a0) - Supplies the starting virtual address and color of the +// data that is flushed. +// +// PageFrame (a1) - Supplies the page frame number of the page that +// is flushed. +// +// Length (a2) - Supplies the length of the region in the page that is +// flushed. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpFlushDcachePageUni) + +#if DBG + + lw t0,KeDcacheFlushCount // get address of dcache flush count + lw t1,0(t0) // increment the count of flushes + addu t1,t1,1 // + sw t1,0(t0) // store result + +#endif + + .set noreorder + .set noat + lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache policy + and a0,a0,COLOR_MASK // isolate color and offset bits + li t0,FLUSH_BASE // get base flush address + or t0,t0,a0 // compute color virtual address + sll t1,a1,ENTRYLO_PFN // shift page frame into position + or t1,t1,PROTECTION_BITS // merge protection bits + or t1,t1,v0 // merge cache policy + and a0,a0,0x1000 // isolate TB entry index + beql zero,a0,10f // if eq, first entry + move t2,zero // set second page table entry + move t2,t1 // set second page table entry + move t1,zero // set first page table entry +10: mfc0 t3,wired // get TB entry index + lw v0,KiPcr + PcSecondLevelDcacheFillSize(zero) // get 2nd fill size + lw t4,KiPcr + PcFirstLevelDcacheFillSize(zero) // get 1st fill size + bnel zero,v0,15f // if ne, second level cache present + move t4,v0 // set flush block size + .set at + .set reorder + +// +// Flush a page from the data cache. +// + +15: DISABLE_INTERRUPTS(t5) // disable interrupts + + .set noreorder + .set noat + mfc0 t6,entryhi // get current PID and VPN2 + srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address + sll t7,t7,ENTRYHI_VPN2 // + and t6,t6,0xff << ENTRYHI_PID // isolate current PID + or t7,t7,t6 // merge PID with VPN2 of virtual address + mtc0 t7,entryhi // set VPN2 and PID for probe + mtc0 t1,entrylo0 // set first PTE value + mtc0 t2,entrylo1 // set second PTE value + mtc0 t3,index // set TB index value + nop // fill + tlbwi // write TB entry - 3 cycle hazzard + subu t6,t4,1 // compute block size minus one + and t7,t0,t6 // compute offset in block + addu a2,a2,t6 // round up to next block + addu a2,a2,t7 // + nor t6,t6,zero // complement block size minus one + and a2,a2,t6 // truncate length to even number + beq zero,a2,30f // if eq, no blocks to flush + and t8,t0,t6 // compute starting virtual address + addu t9,t8,a2 // compute ending virtual address + bne zero,v0,40f // if ne, second level cache present + subu t9,t9,t4 // compute ending loop address + +// +// Flush the primary data cache only. +// + +20: cache HIT_WRITEBACK_INVALIDATE_D,0(t8) // invalidate cache block + bne t8,t9,20b // if ne, more blocks to invalidate + addu t8,t8,t4 // compute next block address + .set at + .set reorder + +30: ENABLE_INTERRUPTS(t5) // enable interrupts + + j ra // return + +// +// Flush the primary and secondary data caches. +// + + .set noreorder + .set noat +40: cache HIT_WRITEBACK_INVALIDATE_SD,0(t8) // invalidate cache block + bne t8,t9,40b // if ne, more blocks to invalidate + addu t8,t8,t4 // compute next block address + .set at + .set reorder + + ENABLE_INTERRUPTS(t5) // enable interrupts + + j ra // return + + .end HalpFlushDcachePageUni + + SBTTL("Purge Data Cache Page") +//++ +// +// VOID +// HalpPurgeDcachePageUni ( +// IN PVOID Color, +// IN ULONG PageFrame, +// IN ULONG Length +// ) +// +// Routine Description: +// +// This function purges (hit/invalidate) up to a page of data from the +// data cache. +// +// Arguments: +// +// Color (a0) - Supplies the starting virtual address and color of the +// data that is purged. +// +// PageFrame (a1) - Supplies the page frame number of the page that +// is purged. +// +// Length (a2) - Supplies the length of the region in the page that is +// purged. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpPurgeDcachePageUni) + +#if DBG + + lw t0,KeDcacheFlushCount // get address of dcache flush count + lw t1,0(t0) // increment the count of flushes + addu t1,t1,1 // + sw t1,0(t0) // store result + +#endif + + .set noreorder + .set noat + lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache policy + and a0,a0,COLOR_MASK // isolate color bits + li t0,FLUSH_BASE // get base flush address + or t0,t0,a0 // compute color virtual address + sll t1,a1,ENTRYLO_PFN // shift page frame into position + or t1,t1,PROTECTION_BITS // merge protection bits + or t1,t1,v0 // merge cache policy + and a0,a0,0x1000 // isolate TB entry index + beql zero,a0,10f // if eq, first entry + move t2,zero // set second page table entry + move t2,t1 // set second page table entry + move t1,zero // set first page table entry +10: mfc0 t3,wired // get TB entry index + lw v0,KiPcr + PcSecondLevelDcacheFillSize(zero) // get 2nd fill size + lw t4,KiPcr + PcFirstLevelDcacheFillSize(zero) // get 1st fill size + bnel zero,v0,15f // if ne, second level cache present + move t4,v0 // set purge block size + .set at + .set reorder + +// +// Purge data from the data cache. +// + +15: DISABLE_INTERRUPTS(t5) // disable interrupts + + .set noreorder + .set noat + mfc0 t6,entryhi // get current PID and VPN2 + srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address + sll t7,t7,ENTRYHI_VPN2 // + and t6,t6,0xff << ENTRYHI_PID // isolate current PID + or t7,t7,t6 // merge PID with VPN2 of virtual address + mtc0 t7,entryhi // set VPN2 and PID for probe + mtc0 t1,entrylo0 // set first PTE value + mtc0 t2,entrylo1 // set second PTE value + mtc0 t3,index // set TB index value + nop // fill + tlbwi // write TB entry - 3 cycle hazzard + subu t6,t4,1 // compute block size minus one + and t7,t0,t6 // compute offset in block + addu a2,a2,t6 // round up to next block + addu a2,a2,t7 // + nor t6,t6,zero // complement block size minus one + and a2,a2,t6 // truncate length to even number + beq zero,a2,30f // if eq, no blocks to purge + and t8,t0,t6 // compute starting virtual address + addu t9,t8,a2 // compute ending virtual address + bne zero,v0,40f // if ne, second level cache present + subu t9,t9,t4 // compute ending loop address + +// +// Purge the primary data cache only. +// + +20: cache HIT_INVALIDATE_D,0(t8) // invalidate cache block + bne t8,t9,20b // if ne, more blocks to invalidate + addu t8,t8,t4 // compute next block address + .set at + .set reorder + +30: ENABLE_INTERRUPTS(t5) // enable interrupts + + j ra // return + +// +// Purge the primary and secondary data caches. +// + + .set noreorder + .set noat +40: cache HIT_INVALIDATE_SD,0(t8) // invalidate cache block + bne t8,t9,40b // if ne, more blocks to invalidate + addu t8,t8,t4 // compute next block address + .set at + .set reorder + + ENABLE_INTERRUPTS(t5) // enable interrupts + + j ra // return + + .end HalpPurgeDcachePageUni + + SBTTL("Purge Instruction Cache Page") +//++ +// +// VOID +// HalpPurgeIcachePageUni ( +// IN PVOID Color, +// IN ULONG PageFrame, +// IN ULONG Length +// ) +// +// Routine Description: +// +// This function purges (hit/invalidate) up to a page of data from the +// instruction cache. +// +// Arguments: +// +// Color (a0) - Supplies the starting virtual address and color of the +// data that is purged. +// +// PageFrame (a1) - Supplies the page frame number of the page that +// is purged. +// +// Length (a2) - Supplies the length of the region in the page that is +// purged. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpPurgeIcachePageUni) + +#if DBG + + lw t0,KeIcacheFlushCount // get address of icache flush count + lw t1,0(t0) // increment the count of flushes + addu t1,t1,1 // + sw t1,0(t0) // store result + +#endif + + .set noreorder + .set noat + lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache policy + and a0,a0,COLOR_MASK // isolate color bits + li t0,FLUSH_BASE // get base flush address + or t0,t0,a0 // compute color virtual address + sll t1,a1,ENTRYLO_PFN // shift page frame into position + or t1,t1,PROTECTION_BITS // merge protection bits + or t1,t1,v0 // merge cache policy + and a0,a0,0x1000 // isolate TB entry index + beql zero,a0,10f // if eq, first entry + move t2,zero // set second page table entry + move t2,t1 // set second page table entry + move t1,zero // set first page table entry +10: mfc0 t3,wired // get TB entry index + lw v0,KiPcr + PcSecondLevelIcacheFillSize(zero) // get 2nd fill size + lw t4,KiPcr + PcFirstLevelIcacheFillSize(zero) // get 1st fill size + bnel zero,v0,15f // if ne, second level cache present + move t4,v0 // set purge block size + .set at + .set reorder + +// +// Purge data from the instruction cache. +// + +15: DISABLE_INTERRUPTS(t5) // disable interrupts + + .set noreorder + .set noat + mfc0 t6,entryhi // get current PID and VPN2 + srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address + sll t7,t7,ENTRYHI_VPN2 // + and t6,t6,0xff << ENTRYHI_PID // isolate current PID + or t7,t7,t6 // merge PID with VPN2 of virtual address + mtc0 t7,entryhi // set VPN2 and PID for probe + mtc0 t1,entrylo0 // set first PTE value + mtc0 t2,entrylo1 // set second PTE value + mtc0 t3,index // set TB index value + nop // fill + tlbwi // write TB entry - 3 cycle hazzard + subu t6,t4,1 // compute block size minus one + and t7,t0,t6 // compute offset in block + addu a2,a2,t6 // round up to next block + addu a2,a2,t7 // + nor t6,t6,zero // complement block size minus one + and a2,a2,t6 // truncate length to even number + beq zero,a2,30f // if eq, no blocks to purge + and t8,t0,t6 // compute starting virtual address + addu t9,t8,a2 // compute ending virtual address + bne zero,v0,40f // if ne, second level cache present + subu t9,t9,t4 // compute ending loop address + +// +// Purge the primary instruction cache only. +// + +20: cache HIT_INVALIDATE_I,0(t8) // invalidate cache block + bne t8,t9,20b // if ne, more blocks to invalidate + addu t8,t8,t4 // compute next block address + .set at + .set reorder + +30: ENABLE_INTERRUPTS(t5) // enable interrupts + + j ra // return + +// +// Purge the primary and secondary instruction caches. +// + + .set noreorder + .set noat +40: cache HIT_INVALIDATE_SI,0(t8) // invalidate cache block + bne t8,t9,40b // if ne, more blocks to invalidate + addu t8,t8,t4 // compute next block address + .set at + .set reorder + + ENABLE_INTERRUPTS(t5) // enable interrupts + + j ra // return + + .end HalpPurgeIcachePageUni + + SBTTL("Sweep Data Cache") +//++ +// +// VOID +// HalpSweepDcacheUni ( +// VOID +// ) +// +// Routine Description: +// +// This function sweeps (index/writeback/invalidate) the entire data cache. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpSweepDcacheUni) + +#if DBG + + lw t0,KeDcacheFlushCount // get address of dcache flush count + lw t1,0(t0) // increment the count of flushes + addu t1,t1,1 // + sw t1,0(t0) // store result + +#endif + +#if defined(ORION) + DISABLE_INTERRUPTS(t5) +#endif + + lw t0,KiPcr + PcFirstLevelDcacheSize(zero) // get data cache size + lw t1,KiPcr + PcFirstLevelDcacheFillSize(zero) // get block size + li a0,KSEG0_BASE // set starting index value + +#if defined(ORION) + +// +// the size is configured on SNI machines as 16KB +// we invalidate in both sets - so divide the configured size by 2 +// + + srl t0,t0,1 +#endif + addu a1,a0,t0 // compute ending cache address + subu a1,a1,t1 // compute ending block address + + +// +// Sweep the primary data cache. +// + + .set noreorder + .set noat +10: + cache INDEX_WRITEBACK_INVALIDATE_D,0(a0) // writeback/invalidate on index + +#if defined(ORION) + cache INDEX_WRITEBACK_INVALIDATE_D,8192(a0) +#endif + + bne a0,a1,10b // if ne, more to invalidate + addu a0,a0,t1 // compute address of next block + .set at + .set reorder + + + lw t0,KiPcr + PcSecondLevelDcacheSize(zero) // get data cache size + lw t1,KiPcr + PcSecondLevelDcacheFillSize(zero) // get block size + beq zero,t1,30f // if eq, no second level cache + li a0,KSEG0_BASE // set starting index value + addu a1,a0,t0 // compute ending cache address + subu a1,a1,t1 // compute ending block address + +// +// Sweep the secondary data cache. +// + + .set noreorder + .set noat +20: cache INDEX_WRITEBACK_INVALIDATE_SD,0(a0) // writeback/invalidate on index + bne a0,a1,20b // if ne, more to invalidate + addu a0,a0,t1 // compute address of next block + .set at + .set reorder + + +30: +#if defined(ORION) + ENABLE_INTERRUPTS(t5) +#endif + + j ra // return + + .end HalpSweepDcacheUni + + SBTTL("Sweep Data Cache Range") +//++ +// +// VOID +// HalSweepDcacheRange ( +// IN PVOID BaseAddress, +// IN ULONG Length +// ) +// +// Routine Description: +// +// This function sweeps (index/writeback/invalidate) the specified range +// of virtual addresses from the primary data cache. +// +// Arguments: +// +// BaseAddress (a0) - Supplies the base address of the range that is swept +// from the data cache. +// +// Length (a1) - Supplies the length of the range that is swept from the +// data cache. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalSweepDcacheRange) + +#if DBG + + lw t0,KeDcacheFlushCount // get address of dcache flush count + lw t1,0(t0) // increment the count of flushes + addu t1,t1,1 // + sw t1,0(t0) // store result conditionally + +#endif + +#if defined(ORION) + DISABLE_INTERRUPTS(t5); +#endif + + and a0,a0,COLOR_MASK // isolate color and offset bits + or a0,a0,KSEG0_BASE // convert to physical address + lw t0,KiPcr + PcFirstLevelDcacheFillSize(zero) // get block size + addu a1,a0,a1 // compute ending cache address + subu a1,a1,t0 // compute ending block address + +// +// Sweep the primary data cache. +// + + + .set noreorder + .set noat +10: cache INDEX_WRITEBACK_INVALIDATE_D,0(a0) // writeback/invalidate on index +#if defined(ORION) + cache INDEX_WRITEBACK_INVALIDATE_D,8192(a0) // do other set on Orion +#endif + bne a0,a1,10b // if ne, more to invalidate + addu a0,a0,t0 // compute address of next block + .set at + .set reorder + +#if defined(ORION) + ENABLE_INTERRUPTS(t5); +#endif + j ra // return + + .end HalSweepDcacheRange + + SBTTL("Sweep Instruction Cache") +//++ +// +// VOID +// HalpSweepIcacheUni ( +// VOID +// ) +// +// Routine Description: +// +// This function sweeps (index/invalidate) the entire instruction cache. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpSweepIcacheUni) + +#if DBG + + lw t0,KeIcacheFlushCount // get address of icache flush count + lw t1,0(t0) // increment the count of flushes + addu t1,t1,1 // + sw t1,0(t0) // store result + +#endif + +#if defined(ORION) + DISABLE_INTERRUPTS(t5); +#endif + + lw t0,KiPcr + PcSecondLevelIcacheSize(zero) // get instruction cache size + lw t1,KiPcr + PcSecondLevelIcacheFillSize(zero) // get fill size + beq zero,t1,20f // if eq, no second level cache + li a0,KSEG0_BASE // set starting index value + addu a1,a0,t0 // compute ending cache address + subu a1,a1,t1 // compute ending block address + + +// +// Sweep the secondary instruction cache. +// + + .set noreorder + .set noat +10: cache INDEX_INVALIDATE_SI,0(a0) // invalidate cache line + bne a0,a1,10b // if ne, more to invalidate + addu a0,a0,t1 // compute address of next block + .set at + .set reorder + +20: lw t0,KiPcr + PcFirstLevelIcacheSize(zero) // get instruction cache size + lw t1,KiPcr + PcFirstLevelIcacheFillSize(zero) // get fill size + li a0,KSEG0_BASE // set starting index value + +#if defined(ORION) + +// +// the size is configured on SNI machines as 16KB +// we invalidate in both sets - so divide the configured size by 2 +// + + srl t0,t0,1 +#endif + addu a1,a0,t0 // compute ending cache address + subu a1,a1,t1 // compute ending block address + +// +// Sweep the primary instruction cache. +// + + + .set noreorder + .set noat +30: cache INDEX_INVALIDATE_I,0(a0) // invalidate cache line + +#if defined(ORION) + cache INDEX_INVALIDATE_I,8192(a0) +#endif + + bne a0,a1,30b // if ne, more to invalidate + addu a0,a0,t1 // compute address of next block + .set at + .set reorder + +#if defined(ORION) + ENABLE_INTERRUPTS(t5); +#endif + + j ra // return + + .end HalpSweepIcacheUni + + SBTTL("Sweep Instruction Cache Range") +//++ +// +// VOID +// HalSweepIcacheRange ( +// IN PVOID BaseAddress, +// IN ULONG Length +// ) +// +// Routine Description: +// +// This function sweeps (index/invalidate) the specified range of addresses +// from the instruction cache. +// +// Arguments: +// +// BaseAddress (a0) - Supplies the base address of the range that is swept +// from the instruction cache. +// +// Length (a1) - Supplies the length of the range that is swept from the +// instruction cache. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalSweepIcacheRange) + +#if DBG + + lw t0,KeIcacheFlushCount // get address of icache flush count + lw t1,0(t0) // increment the count of flushes + addu t1,t1,1 // + sw t1,0(t0) // store result + +#endif + +#if defined(ORION) + DISABLE_INTERRUPTS(t5); +#endif + + and a0,a0,COLOR_MASK // isolate color and offset bits + or a0,a0,KSEG0_BASE // convert to physical address + lw t0,KiPcr + PcFirstLevelIcacheFillSize(zero) // get fill size + addu a1,a0,a1 // compute ending cache address + subu a1,a1,t0 // compute ending block address + +// +// Sweep the primary instruction cache. +// + + + .set noreorder + .set noat +10: + + cache INDEX_INVALIDATE_I,0(a0) // invalidate cache line + +#if defined(ORION) + cache INDEX_INVALIDATE_I,8192(a0) // do set B first on Orion +#endif + + bne a0,a1,10b // if ne, more to invalidate + addu a0,a0,t0 // compute address of next block + .set at + .set reorder + +#if defined(ORION) + ENABLE_INTERRUPTS(t5); +#endif + + j ra // return + + .end HalSweepIcacheRange + + + SBTTL("Zero Page") +//++ +// +// VOID +// HalpZeroPageUni ( +// IN PVOID NewColor, +// IN PVOID OldColor, +// IN ULONG PageFrame +// ) +// +// Routine Description: +// +// This function zeros a page of memory. +// +// The algorithm used to zero a page is as follows: +// +// 1. Purge (hit/invalidate) the page from the instruction cache +// using the old color iff the old color is not the same as +// the new color. +// +// 2. Purge (hit/invalidate) the page from the data cache using +// the old color iff the old color is not the same as the new +// color. +// +// 3. Create (create/dirty/exclusive) the page in the data cache +// using the new color. +// +// 4. Write zeros to the page using the new color. +// +// Arguments: +// +// NewColor (a0) - Supplies the page aligned virtual address of the +// new color of the page that is zeroed. +// +// OldColor (a1) - Supplies the page aligned virtual address of the +// old color of the page that is zeroed. +// +// PageFrame (a2) - Supplies the page frame number of the page that +// is zeroed. +// +// Return Value: +// +// None. +// +//-- + + .struct 0 + .space 3 * 4 // fill +ZpRa: .space 4 // saved return address +ZpFrameLength: // length of stack frame +ZpA0: .space 4 // (a0) +ZpA1: .space 4 // (a1) +ZpA2: .space 4 // (a2) +ZpA3: .space 4 // (a3) + + NESTED_ENTRY(HalpZeroPageUni, ZpFrameLength, zero) + + subu sp,sp,ZpFrameLength // allocate stack frame + sw ra,ZpRa(sp) // save return address + + PROLOGUE_END + + and a0,a0,COLOR_BITS // isolate new color bits + and a1,a1,COLOR_BITS // isolate old color bits + sw a0,ZpA0(sp) // save new color bits + sw a1,ZpA1(sp) // save old color bits + sw a2,ZpA2(sp) // save page frame + +// +// If the old page color is not equal to the new page color, then change +// the color of the page. +// + + beq a0,a1,10f // if eq, colors match +// +// Purge the instruction cache using the old page color. +// + + move a0,a1 // set color value + move a1,a2 // set page frame number + li a2,PAGE_SIZE // set length of purge + jal HalPurgeIcachePage // purge instruction cache page + +// +// Flush the data cache using the old page color. +// + + lw a0,ZpA1(sp) // get old color bits + lw a1,ZpA2(sp) // get page frame number + li a2,PAGE_SIZE // set length of purge + jal HalPurgeDcachePage // purge data cache page + +// +// Create dirty exclusive cache blocks and zero the data. +// + +10: lw a3,ZpA0(sp) // get new color bits + lw a1,ZpA2(sp) // get page frame number + + .set noreorder + .set noat + lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache polciy + li t0,FLUSH_BASE // get base flush address + or t0,t0,a3 // compute new color virtual address + sll t1,a1,ENTRYLO_PFN // shift page frame into position + or t1,t1,PROTECTION_BITS // merge protection bits + or t1,t1,v0 // merge cache policy + and a3,a3,0x1000 // isolate TB entry index + beql zero,a3,20f // if eq, first entry + move t2,zero // set second page table entry + move t2,t1 // set second page table entry + move t1,zero // set first page table entry +20: mfc0 t3,wired // get TB entry index + lw t4,KiPcr + PcFirstLevelDcacheFillSize(zero) // get 1st fill size + lw v0,KiPcr + PcSecondLevelDcacheFillSize(zero) // get 2nd fill size + .set at + .set reorder + + DISABLE_INTERRUPTS(t5) // disable interrupts + + .set noreorder + .set noat + mfc0 t6,entryhi // get current PID and VPN2 + srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address + sll t7,t7,ENTRYHI_VPN2 // + and t6,t6,0xff << ENTRYHI_PID // isolate current PID + or t7,t7,t6 // merge PID with VPN2 of virtual address + mtc0 t7,entryhi // set VPN2 and PID for probe + mtc0 t1,entrylo0 // set first PTE value + mtc0 t2,entrylo1 // set second PTE value + mtc0 t3,index // set TB index value + nop // fill + tlbwi // write TB entry - 3 cycle hazzard + addu t9,t0,PAGE_SIZE // compute ending address of block + dmtc1 zero,f0 // set write pattern + bne zero,v0,50f // if ne, second level cache present + and t8,t4,0x10 // test if 16-byte cache block + +// +// Zero page in primary data cache only. +// + + +30: cache CREATE_DIRTY_EXCLUSIVE_D,0(t0) // create cache block + addu t0,t0,t4 // compute next block address + bne zero,t8,40f // if ne, 16-byte cache line + sdc1 f0,-16(t0) // + sdc1 f0,-24(t0) // zero 16 bytes + sdc1 f0,-32(t0) // +40: bne t0,t9,30b // if ne, more blocks to zero + sdc1 f0,-8(t0) // zero 16 bytes + + + .set at + .set reorder + + ENABLE_INTERRUPTS(t5) // enable interrupts + + lw ra,ZpRa(sp) // get return address + addu sp,sp,ZpFrameLength // deallocate stack frame + j ra // return + +// +// Zero page in primary and secondary data caches. +// + + .set noreorder + .set noat + + +50: cache CREATE_DIRTY_EXCLUSIVE_SD,0(t0) // create secondary cache block + addu v1,v0,t0 // compute ending primary block address +60: addu t0,t0,t4 // compute next block address + bne zero,t8,70f // if ne, 16-byte primary cache line + sdc1 f0,-16(t0) // + sdc1 f0,-24(t0) // zero 16 bytes + sdc1 f0,-32(t0) // +70: bne t0,v1,60b // if ne, more primary blocks to zero + sdc1 f0,-8(t0) // zero 16 bytes + bne t0,t9,50b // if ne, more secondary blocks to zero + nop // fill + + .set at + .set reorder + + ENABLE_INTERRUPTS(t5) // enable interrupts + + lw ra,ZpRa(sp) // get return address + addu sp,sp,ZpFrameLength // deallocate stack frame + j ra // return + + .end HalpZeroPageUni + + + + + LEAF_ENTRY(HalpPciEccCorrector) +// a0 : offset +// a1 : pfn +// a2 : length + + .set noreorder + .set noat + and a0,a0,PAGE_SIZE -1 // PageOffset + lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache policy + li t0,FLUSH_BASE // get base flush address + or t0,t0,a0 // compute color virtual address + sll t1,a1,ENTRYLO_PFN // shift page frame into position + or t1,t1,PROTECTION_BITS // merge protection bits + or t1,t1,v0 // merge cache policy + and a0,a0,0x1000 // isolate TB entry index + beql zero,a0,10f // if eq, first entry + move t2,zero // set second page table entry + move t2,t1 // set second page table entry + move t1,zero // set first page table entry +10: mfc0 t3,wired // get TB entry index + lw v0,KiPcr + PcSecondLevelDcacheFillSize(zero) // get 2nd fill size + lw t4,KiPcr + PcFirstLevelDcacheFillSize(zero) // get 1st fill size + bnel zero,v0,15f // if ne, second level cache present + move t4,v0 // set flush block size + .set at + .set reorder + +// +// Flush a page from the data cache. +// + +15: DISABLE_INTERRUPTS(t5) // disable interrupts + + .set noreorder + .set noat + mfc0 t6,entryhi // get current PID and VPN2 + srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address + sll t7,t7,ENTRYHI_VPN2 // + and t6,t6,0xff << ENTRYHI_PID // isolate current PID + or t7,t7,t6 // merge PID with VPN2 of virtual address + mtc0 t7,entryhi // set VPN2 and PID for probe + mtc0 t1,entrylo0 // set first PTE value + mtc0 t2,entrylo1 // set second PTE value + mtc0 t3,index // set TB index value + nop // fill + tlbwi // write TB entry - 3 cycle hazzard + + ENABLE_INTERRUPTS(t5) // enable interrupts + .set noreorder + .set noat + + subu t6,t4,1 // compute block size minus one + and t7,t0,t6 // compute offset in block + addu a2,a2,t6 // round up to next block + addu a2,a2,t7 // + nor t6,t6,zero // complement block size minus one + and a2,a2,t6 // truncate length to even number + and t8,t0,t6 // compute starting virtual address + addu t9,t8,a2 // compute ending virtual address + subu t9,t9,t4 // compute ending loop address + +// beq zero,v0,40f // if eq, no second level cache + +// +// Flush the secondary data cache. +// + +20: lw t7,0(t8) + sw t7,0(t8) + cache HIT_WRITEBACK_INVALIDATE_SD,0(t8) // invalidate cache block + + nop + nop + + bne t8,t9,20b // if ne, more blocks to invalidate + addu t8,t8,t4 // compute next block address +40: + + j ra // return + + .end HalpPciEccCorrector + + diff --git a/private/ntos/nthals/halsnip/mips/vgadata.h b/private/ntos/nthals/halsnip/mips/vgadata.h new file mode 100644 index 000000000..a996b85a7 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/vgadata.h @@ -0,0 +1,420 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/vgadata.h,v 1.3 1995/11/02 11:04:33 flo Exp $") + +#define MAX_CRT 0x19 +#define GRAPH_MAX 0x9 +#define MAX_PALETTE 0x15 + +// VGA constants + +#define REVERSE_ATTRIBUTE 0x17 // white on blue + +#define INIT_VGA_FONT() \ + WRITE_REGISTER_UCHAR(VGA_SEQ_IDX, 0x02); \ + WRITE_REGISTER_UCHAR(VGA_SEQ_DATA, 0x04); \ + WRITE_REGISTER_UCHAR(VGA_SEQ_IDX, 0x04); \ + WRITE_REGISTER_UCHAR(VGA_SEQ_DATA, 0x06); \ + WRITE_REGISTER_UCHAR(VGA_GRAPH_IDX, 0x05); \ + WRITE_REGISTER_UCHAR(VGA_GRAPH_DATA, 0x08); \ + WRITE_REGISTER_UCHAR(VGA_GRAPH_IDX, 0x06); \ + WRITE_REGISTER_UCHAR(VGA_GRAPH_DATA, 0x01); + +#define EXIT_VGA_FONT() \ + WRITE_REGISTER_UCHAR(VGA_SEQ_IDX, 0x02); \ + WRITE_REGISTER_UCHAR(VGA_SEQ_DATA, 0x03); \ + WRITE_REGISTER_UCHAR(VGA_SEQ_IDX, 0x04); \ + WRITE_REGISTER_UCHAR(VGA_SEQ_DATA, 0x02); \ + WRITE_REGISTER_UCHAR(VGA_GRAPH_IDX, 0x04); \ + WRITE_REGISTER_UCHAR(VGA_GRAPH_DATA, 0x00); \ + WRITE_REGISTER_UCHAR(VGA_GRAPH_IDX, 0x05); \ + WRITE_REGISTER_UCHAR(VGA_GRAPH_DATA, 0x10); \ + WRITE_REGISTER_UCHAR(VGA_GRAPH_IDX, 0x06); \ + WRITE_REGISTER_UCHAR(VGA_GRAPH_DATA, 0x0e); + + +// +// Adresses for the Bt485 RamDac on the Orchid VLB and Diamond Viper board +// + +#define Bt485_MASK ((PVOID) ((ULONG)HalpVGAControlBase + 0x03c6)) +#define Bt485_ADDRRD ((PVOID) ((ULONG)HalpVGAControlBase + 0x03c7)) +#define Bt485_ADDR ((PVOID) ((ULONG)HalpVGAControlBase + 0x03c8)) +#define Bt485_DATA ((PVOID) ((ULONG)HalpVGAControlBase + 0x03c9)) +#define Bt485_CR0 ((PVOID) ((ULONG)HalpVGAControlBase + 0x43c6)) +#define Bt485_ADDRCURRD ((PVOID) ((ULONG)HalpVGAControlBase + 0x43c7)) +#define Bt485_ADDRCUR ((PVOID) ((ULONG)HalpVGAControlBase + 0x43c8)) +#define Bt485_DATACUR ((PVOID) ((ULONG)HalpVGAControlBase + 0x43c9)) +#define Bt485_STATUS ((PVOID) ((ULONG)HalpVGAControlBase + 0x83c6)) +#define Bt485_CR3 ((PVOID) ((ULONG)HalpVGAControlBase + 0x83c6)) /* if enabled */ +#define Bt485_CURSORRAM ((PVOID) ((ULONG)HalpVGAControlBase + 0x83c7)) +#define Bt485_CR1 ((PVOID) ((ULONG)HalpVGAControlBase + 0x83c8)) +#define Bt485_CR2 ((PVOID) ((ULONG)HalpVGAControlBase + 0x83c9)) +#define Bt485_CURSOR_YL ((PVOID) ((ULONG)HalpVGAControlBase + 0xc3c6)) +#define Bt485_CURSOR_YH ((PVOID) ((ULONG)HalpVGAControlBase + 0xc3c7)) +#define Bt485_CURSOR_XL ((PVOID) ((ULONG)HalpVGAControlBase + 0xc3c8)) +#define Bt485_CURSOR_XH ((PVOID) ((ULONG)HalpVGAControlBase + 0xc3c9)) + +// Some VGA Registers + +#define VGA_MISC_READ ((PVOID) ((ULONG)HalpVGAControlBase + 0x03cc)) +#define VGA_MISC_WRITE ((PVOID) ((ULONG)HalpVGAControlBase + 0x03c2)) +#define VGA_SEQ_IDX ((PVOID) ((ULONG)HalpVGAControlBase + 0x03c4)) +#define VGA_SEQ_DATA ((PVOID) ((ULONG)HalpVGAControlBase + 0x03c5)) +#define VGA_CRT_IDX ((PVOID) ((ULONG)HalpVGAControlBase + 0x03d4)) +#define VGA_CRT_DATA ((PVOID) ((ULONG)HalpVGAControlBase + 0x03d5)) +#define VGA_ATC_IDX ((PVOID) ((ULONG)HalpVGAControlBase + 0x03c0)) +#define VGA_ATC_DATA ((PVOID) ((ULONG)HalpVGAControlBase + 0x03c0)) +#define VGA_GRAPH_IDX ((PVOID) ((ULONG)HalpVGAControlBase + 0x03ce)) +#define VGA_GRAPH_DATA ((PVOID) ((ULONG)HalpVGAControlBase + 0x03cf)) +#define VGA_ATC_FF ((PVOID) ((ULONG)HalpVGAControlBase + 0x03da)) +#define VGA_DAC_MASK ((PVOID) ((ULONG)HalpVGAControlBase + 0x03c6)) +#define VGA_DAC_STATUS ((PVOID) ((ULONG)HalpVGAControlBase + 0x03c7)) +#define VGA_DAC_WRITE_INDEX ((PVOID) ((ULONG)HalpVGAControlBase + 0x03c8)) +#define VGA_DAC_DATA ((PVOID) ((ULONG)HalpVGAControlBase + 0x03c9)) +#define VGA_FEAT_CNTRL ((PVOID) ((ULONG)HalpVGAControlBase + 0x03ca)) +#define S3_ADVFUNC_CNTL ((PVOID) ((ULONG)HalpVGAControlBase + 0x4ae8)) + +// the same registers as offset for use in SetHwMode() + +#define MISC_READ 0x03cc +#define MISC_WRITE 0x03c2 +#define SEQ_IDX 0x03c4 +#define SEQ_DATA 0x03c5 +#define CRT_IDX 0x03d4 +#define CRT_DATA 0x03d5 +#define ATC_IDX 0x03c0 +#define ATC_DATA 0x03c0 +#define GRAPH_IDX 0x03ce +#define GRAPH_DATA 0x03cf +#define ATC_FF 0x03da +#define DAC_MASK 0x03c6 +#define DAC_STATUS 0x03c7 +#define DAC_WRITE_INDEX 0x03c8 +#define DAC_DATA 0x03c9 +#define FEAT_CNTRL 0x03ca + +// S3 Advanced Function control register + +#define ADVFUNC_CNTL 0x4ae8 + +#define MAGIC_REG1 0x46e8 +#define MAGIC_REG2 0x0102 +#define CIRRUS_MAGIC1 0x03c3 +#define CIRRUS_MAGIC2 0x0094 + +// +// "magic" registers to enable the Video System on VGA +// for non Intel Systems +// +#define VGA_MAGIC_REG1 ((PVOID) ((ULONG)HalpVGAControlBase + 0x46e8)) +#define VGA_MAGIC_REG2 ((PVOID) ((ULONG)HalpVGAControlBase + 0x0102)) +#define CIRRUS_MAGIC_REG1 ((PVOID) ((ULONG)HalpVGAControlBase + 0x03c3)) +#define CIRRUS_MAGIC_REG2 ((PVOID) ((ULONG)HalpVGAControlBase + 0x0094)) + + +UCHAR base_colors[] = { + 0, 0, 0, // color 0 (black) + 0, 0, 42, // color 1 (drk. blue) + 0, 42, 0, // color 2 (olive) + 0, 42, 42, // color 3 () +42, 0, 0, // color 4 (brown) +42, 0, 42, // color 5 (turquise) +42, 21, 0, // color 6 (tundra ) +63, 63, 63, // color 7 (lt. grey(42,42,42 but we set it to white) +21, 21, 21, // color 8 (drk. grey) +21, 21, 63, // color 9 (blue) +21, 63, 21, // color 10 (green) +21, 63, 63, // color 11 (lt. blue) +63, 0, 0, // color 12 (red) +63, 0, 63, // color 13 (cyan) +63, 63, 0, // color 14 (yellow) +63, 63, 63 // color 15 (white) +}; + +// +// this is an VGA 8x8 font (Codepage 437) +// + +UCHAR font_8x8[] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //0x00 +0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e, //0x01 +0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e, //0x02 +0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, //0x03 +0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, +0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c, +0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c, +0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, +0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, +0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, +0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, +0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78, +0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, +0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0, +0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0, +0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99, +0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00, +0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00, +0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18, +0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00, +0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00, +0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78, +0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00, +0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff, +0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00, +0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, +0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, +0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, +0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, +0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, +0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00, +0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00, +0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, +0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, +0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00, +0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00, +0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00, +0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, +0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, +0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, +0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, +0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60, +0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, +0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, +0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00, +0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00, +0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00, +0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00, +0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00, +0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00, +0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00, +0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00, +0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00, +0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00, +0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00, +0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60, +0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00, +0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00, // = +0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00, // > +0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00, // ? +0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00, // @ +0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00, // A +0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00, // B +0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00, // C +0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, // D +0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00, // E +0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00, +0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00, +0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00, +0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, +0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, +0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00, +0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, +0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00, +0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00, +0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, +0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, +0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00, +0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00, +0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00, +0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, +0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00, +0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00, +0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00, +0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00, +0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00, +0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00, +0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00, +0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00, +0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00, +0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, +0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, +0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00, +0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00, +0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, +0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, +0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00, +0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, +0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00, +0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, +0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, +0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00, +0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, +0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00, +0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00, +0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00, +0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0, +0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e, +0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00, +0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00, +0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00, +0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, +0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00, +0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00, +0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00, +0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, +0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00, +0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00, +0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, +0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00, +0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00, +0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x18, 0x0c, 0x78, // 8 bit codes 0x80 +0x00, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00, // 0x81 ü +0x1c, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, // 0x82 é +0x7e, 0xc3, 0x3c, 0x06, 0x3e, 0x66, 0x3f, 0x00, // 0x83 â +0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, // 0x84 ä +0xe0, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, // 0x85 à +0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, // 0x86°a +0x00, 0x00, 0x78, 0xc0, 0xc0, 0x78, 0x0c, 0x38, // 0x87,c +0x7e, 0xc3, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00, // 0x88 ê +0xcc, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, // 0x89 ..e +0xe0, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, // 0x8a è +0xcc, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, // 0x8b ..i +0x7c, 0xc6, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, // 0x8c î +0xe0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, // 0x8d ì +0xc6, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, // 0x8e Ä +0x30, 0x30, 0x00, 0x78, 0xcc, 0xfc, 0xcc, 0x00, // 0x8f °A +0x1c, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00, // 0x90 +0x00, 0x00, 0x7f, 0x0c, 0x7f, 0xcc, 0x7f, 0x00, // 0x91 +0x3e, 0x6c, 0xcc, 0xfe, 0xcc, 0xcc, 0xce, 0x00, // 0x92 +0x78, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, // 0x93 ô +0x00, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, // 0x94 ö +0x00, 0xe0, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, // 0x95 ò +0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00, // 0x96 û +0x00, 0xe0, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00, // 0x97 ù +0x00, 0xcc, 0x00, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, // 0x98 ..y +0xc3, 0x18, 0x3c, 0x66, 0x66, 0x3c, 0x18, 0x00, // 0x99 Ö +0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, // 0x9a ü +0x18, 0x18, 0x7e, 0xc0, 0xc0, 0x7e, 0x18, 0x18, // 0x9b +0x38, 0x6c, 0x64, 0xf0, 0x60, 0xe6, 0xfc, 0x00, // 0x9c +0xcc, 0xcc, 0x78, 0xfc, 0x30, 0xfc, 0x30, 0x30, // 0x9d +0xf8, 0xcc, 0xcc, 0xfa, 0xc6, 0xcf, 0xc6, 0xc7, // 0x9e +0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70, // 0x9f +0x1c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, +0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, +0x00, 0x1c, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, +0x00, 0x1c, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00, +0x00, 0xf8, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0x00, +0xfc, 0x00, 0xcc, 0xec, 0xfc, 0xdc, 0xcc, 0x00, +0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, +0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, +0x30, 0x00, 0x30, 0x60, 0xc0, 0xcc, 0x78, 0x00, +0x38, 0x74, 0xaa, 0xba, 0xaa, 0x64, 0x38, 0x00, // (R) +0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00, +0xc3, 0xc6, 0xcc, 0xde, 0x33, 0x66, 0xcc, 0x0f, +0xc3, 0xc6, 0xcc, 0xdb, 0x37, 0x6f, 0xcf, 0x03, +0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, +0x00, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x00, 0x00, +0x00, 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00, +0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, +0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, +0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, +0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, +0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, +0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, +0x3c, 0x42, 0x99, 0xa1, 0xa1, 0x99, 0x42, 0x3c, // (c) +0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, +0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, +0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, +0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, +0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, +0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, +0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, +0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, +0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, +0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, +0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, +0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, +0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, +0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, +0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, +0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, +0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, +0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, +0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, +0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, +0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, +0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, +0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x76, 0xdc, 0xc8, 0xdc, 0x76, 0x00, +0x00, 0x78, 0xcc, 0xf8, 0xcc, 0xf8, 0xc0, 0xc0, +0x00, 0xfc, 0xcc, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, +0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, +0xfc, 0xcc, 0x60, 0x30, 0x60, 0xcc, 0xfc, 0x00, +0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0x70, 0x00, +0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0xc0, +0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x00, +0xfc, 0x30, 0x78, 0xcc, 0xcc, 0x78, 0x30, 0xfc, +0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x6c, 0x38, 0x00, +0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x6c, 0xee, 0x00, +0x1c, 0x30, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00, +0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00, +0x06, 0x0c, 0x7e, 0xdb, 0xdb, 0x7e, 0x60, 0xc0, +0x38, 0x60, 0xc0, 0xf8, 0xc0, 0x60, 0x38, 0x00, +0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00, +0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x00, +0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0xfc, 0x00, +0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xfc, 0x00, +0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xfc, 0x00, +0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70, +0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00, +0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, +0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, +0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c, +0x78, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, +0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00, +0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +#define STORM_OFFSET 0x1c00 +#define STORM_MISC_W 0x3c2 +#define STORM_PCI_OPTION 0x40 + +#define STORM_RAMDAC_OFFSET 0x3c00 +#define STORM_TVP3026_INDEX 0x00 +#define STORM_TVP3026_DATA 0x0a + +#define STORM_TVP3026_PIX_CLK_DATA 0x2d +#define STORM_TVP3026_MEM_CLK_DATA 0x2e +#define STORM_TVP3026_MCLK_CTL 0x39 + +#define STORM_TVP3026_PLL_ADDR 0x2c +#define STORM_TVP3026_PLL_RESET 0xff + +#define VGA_CRTCEXT_IDX ((PVOID) ((ULONG)HalpVGAControlBase + 0x03de)) +#define VGA_CRTCEXT_DATA ((PVOID) ((ULONG)HalpVGAControlBase + 0x03df)) +#define VGA_CRTCEXT0 0x00 +#define VGA_CRTCEXT1 0x01 +#define VGA_CRTCEXT2 0x02 +#define VGA_CRTCEXT3 0x03 +#define VGA_CRTCEXT4 0x04 +#define VGA_CRTCEXT5 0x05 + +#define STORM_STATUS 0x214 diff --git a/private/ntos/nthals/halsnip/mips/x4clock.s b/private/ntos/nthals/halsnip/mips/x4clock.s new file mode 100644 index 000000000..82df85dee --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/x4clock.s @@ -0,0 +1,457 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/x4clock.s,v 1.6 1996/03/12 14:56:20 pierre Exp $") + +// TITLE("Interval and Profile Clock Interrupts") +//++ +// +// Copyright (c) 1991 Microsoft Corporation +// +// Module Name: +// +// x4clock.s +// +// Abstract: +// +// This module implements the code necessary to field and process the +// interval and profile clock interrupts on a MIPS R4000 system. +// +// Environment: +// +// Kernel mode only. +// +// +//-- + +#include "halmips.h" +#include "SNIdef.h" + +#define MPA_TIMER_MESSAGE 11 /* timer interrupt */ + + + SBTTL("System Clock Interrupt") +//++ +// +// Routine Description: +// +// This routine is entered as the result of an interrupt generated by +// the interval timer. Its function is to acknowledge the interrupt and +// transfer control to the standard system routine to update the system +// time and the execution time of the current thread and process. +// +// Arguments: +// +// s8 - Supplies a pointer to a trap frame. +// +// Return Value: +// +// None. +// +//-- + + + .struct 0 +CiArgs: .space 4 * 4 // saved arguments + .space 3 * 4 // fill +CiRa: .space 4 // saved return address +CiFrameLength: // + + NESTED_ENTRY(HalpClockInterrupt, CiFrameLength, zero) + + + subu sp,sp,CiFrameLength // allocate stack frame + sw ra,CiRa(sp) // save return address + + PROLOGUE_END + + move a0,s8 // set address of trap frame + lw a1,HalpCurrentTimeIncrement + lw t0,__imp_KeUpdateSystemTime // update system time + jal t0 // + +// +// we use this only when we have the machine up and running ... +// LED's can show us something, what we do not see in the debugger +// + + la t0,HalpLedRegister // get current Value of LED Register + lw a0,0(t0) + addu a0,a0,1 // increment + sw a0,0(t0) // store and + + lw t0,HalpIsTowerPci + beq t0,zero,2f + jal HalpPciTowerDisplayLed + b 3f + +2: + la t0, HalpLedAddress // get address of the variable + lw t0,0(t0) // get value + sb a0,0(t0) // display LSByte (set the LED) + +// +// At each clock interrupt the next time increment is moved to the current +// time increment to "pipeline" the update of the current increment at the +// correct time. If the new time increment is nonzero, then the new time +// increment is moved to the next time increment and the timer is reprogramed +// + +3: lw t0,KdDebuggerEnabled // get address of debugger enable + lw t1,HalpNewTimeIncrement // get new time increment + lw t2,HalpNextTimeIncrement // get the next increment value + lbu t0,0(t0) // get debugger enable flag + lw ra,CiRa(sp) // restore return address + or t4,t1,t0 // new interval count or debugger? + sw t2,HalpCurrentTimeIncrement // pipeline current increment value + bne zero,t4,10f // if ne, interval change or debugger + addu sp,sp,CiFrameLength // deallocate stack frame + j ra // return + +// +// The interval count must be changed or the debugger is enabled. +// + +10: sw zero,HalpNewTimeIncrement // clear new time increment + beq zero,t1,15f // if eq, not interval count change + sw t1,HalpNextTimeIncrement // set next time increment value + move a0,t1 // prepare to call HalpProgramIntervalTimer + jal HalpProgramIntervalTimer // program timer chip ... +15: beq zero,t0,40f // if eq, debugger not enabled + jal KdPollBreakIn // check if breakin is requested + beq zero,v0,40f // if eq, no breakin requested + break BREAKIN_BREAKPOINT // break into the debugger + +40: lw ra,CiRa(sp) // restore return address + addu sp,sp,CiFrameLength // deallocate stack frame + j ra // return + + .end HalpClockInterrupt + + + SBTTL("System Clock Interrupt - Processor N") +//++ +// +// Routine Description: +// +// This routine is entered as the result of an interrupt generated by +// the extra interval timer in the slave processors. Its function is +// to transfer control to the standard system routine to update the +// execution time of the current thread and process. +// +// Note: We plan to use the extra timer for our MultiProcessor (SNI)Machine +// MAYBE, if we have arbitrated interrupts, we have to acknowledge +// this interrupt here and send an message to the other processors +// (Quadro machine) +// +// Arguments: +// +// s8 - Supplies a pointer to a trap frame. +// +// Return Value: +// +// None. +// +//-- + + NESTED_ENTRY(HalpClockInterrupt1, CiFrameLength, zero) + + subu sp,sp,CiFrameLength // allocate stack frame + sw ra,CiRa(sp) // save return address + + PROLOGUE_END + + li a0,0x1000 + jal HalpCheckSpuriousInt + beq v0,0,10f + lw ra,CiRa(sp) // restore return address + addu sp,sp,CiFrameLength // deallocate stack frame + j ra + +10: + li t0, PCI_EXTRA_TIMER_ACK_ADDR // get address of acknowledge register + sb zero,0(t0) // acknowledge timer interrupt + + move a0,s8 // set address of trap frame + lw t1,__imp_KeUpdateRunTime // update system runtime + lw ra,CiRa(sp) // restore return address + addu sp,sp,CiFrameLength // deallocate stack frame + j t1 // + .end HalpClockInterrupt1 + + SBTTL("System Clock Interrupt - Processor N") +//++ +// +// Routine Description: +// +// This routine is entered as the result of an interrupt generated by +// the extra interval timer in the slave processors. Its function is +// to transfer control to the standard system routine to update the +// execution time of the current thread and process. +// +// We use the extra timer for our MultiProcessor (SNI)Machine +// we have to acknowledge +// this interrupt here and send an message to the other processors +// (Quadro machine) +// +// Arguments: +// +// s8 - Supplies a pointer to a trap frame. +// +// Return Value: +// +// None. +// +//-- + + NESTED_ENTRY(HalpClockInterruptPciTower, CiFrameLength, zero) + + subu sp,sp,CiFrameLength // allocate stack frame + sw ra,CiRa(sp) // save return address + + PROLOGUE_END + + + + // + // Send a "TIMER" ipi + // + lw a0,HalpIsMulti // test if more than 2 procs + li a1,2 + slt a2,a1,a0 + beq a2,0,10f // if no more than 2 proc , no need to send Ipi + + li a0,0xc // send IPI to proc 2 and 3 + li a1,MPA_TIMER_MESSAGE + jal HalpRequestIpi + +10: move a0,s8 // set address of trap frame + lw t1,__imp_KeUpdateRunTime // update system runtime + lw ra,CiRa(sp) // restore return address + addu sp,sp,CiFrameLength // deallocate stack frame + j t1 // + .end HalpClockInterruptPciTower + + + SBTTL("Profile Clock Interrupt") +//++ +// +// Routine Description: +// +// This routine is entered as the result of an interrupt generated by the +// profile clock. Its function is to acknowledge the profile interrupt, +// compute the next compare value, update the performance counter, and +// transfer control to the standard system routine to process any active +// profiles. +// +// Arguments: +// +// s8 - Supplies a pointer to a trap frame. +// +// Return Value: +// +// None. +// +//-- + + NESTED_ENTRY(HalpProfileInterrupt, CiFrameLength, zero) + + subu sp,sp,CiFrameLength // allocate stack frame + sw ra,CiRa(sp) // save return address + + PROLOGUE_END + +// li a0,0x8000 +// jal HalpCheckSpuriousInt +// beq v0,zero,10f +// lw ra,CiRa(sp) // restore return address +// addu sp,sp,CiFrameLength // deallocate stack frame +// j ra + +10: .set noreorder + .set noat + mfc0 t1,count // get current count value + mfc0 t0,compare // get current comparison value + addu t1,t1,8 // factor in lost cycles + subu t1,t1,t0 // compute initial count value + mtc0 t0,compare // dismiss interrupt + mtc0 t1,count // set new count register value + .set at + .set reorder + + + +// +// we prefer the MultiPro version, which also works on UniPro machines +// + + lw t1,KiPcr + PcPrcb(zero) // get current processor block address + la t2,HalpPerformanceCounter // get performance counter address + lbu t1,PbNumber(t1) // get processor number + sll t1,t1,3 // compute address of performance count + addu t1,t1,t2 // + + lw t2,LiLowPart(t1) // get low part of performance count + lw t3,LiHighPart(t1) // get high part of performance count + addu t2,t2,t0 // update low part of performance count + sw t2,LiLowPart(t1) // store low part of performance count + sltu t4,t2,t0 // generate carry into high part + addu t3,t3,t4 // update high part of performance count + sw t3,LiHighPart(t1) // store high part of performance count + li a0,0x00 + move a0,s8 // set address of trap frame + lw t4,__imp_KeProfileInterrupt // process profile interrupt + jal t4 // + + + + jal HalpCheckSpuriousInt + lw ra,CiRa(sp) // restore return address + addu sp,sp,CiFrameLength // deallocate stack frame + j ra + .end HalpProfileInterrupt + + + SBTTL("Read Count Register") +//++ +// +// ULONG +// HalpReadCountRegister ( +// VOID +// ); +// +// Routine Description: +// +// This routine reads the current value of the count register and +// returns the value. +// +// Arguments: +// +// None. +// +// Return Value: +// +// Current value of the count register. +// +//-- + + LEAF_ENTRY(HalpReadCountRegister) + + .set noreorder + .set noat + mfc0 v0,count // get count register value + .set at + .set reorder + + j ra // return + + .end HalpReadCountRegister + + SBTTL("Write Compare Register And Clear") +//++ +// +// ULONG +// HalpWriteCompareRegisterAndClear ( +// IN ULONG Value +// ); +// +// Routine Description: +// +// This routine reads the current value of the count register, writes +// the value of the compare register, clears the count register, and +// returns the previous value of the count register. +// +// Arguments: +// +// Value - Supplies the value written to the compare register. +// +// Return Value: +// +// Previous value of the count register. +// +//-- + + LEAF_ENTRY(HalpWriteCompareRegisterAndClear) + + .set noreorder + .set noat + mfc0 v0,count // get count register value + mtc0 a0,compare // set compare register value + li t0,7 // set lost cycle count + mtc0 t0,count // set count register to zero + .set at + .set reorder + + j ra // return + + .end HalpWriteCompareRegisterAndClear + + NESTED_ENTRY(HalpPciTowerDisplayLed, CiFrameLength, zero) + + subu sp,sp,CiFrameLength // allocate stack frame + sw ra,CiRa(sp) // save return address + + PROLOGUE_END + + + // + // code for PCI tower + // + li t5,8, + divu a0,t5 + mfhi t4 + li t5,1 + .word 0x018d2004 # sllv a0,t5,t4 + + +// t4 -> temp-reg. +// t5 -> low-reg. 32 bits +// t6 -> high-reg. 32 bits + + and t5,a0,0x01 # bit0 shift to bit0(LED0) + + and t4,a0,0x02 # bit1 shift to bit16(LED1) + sll t4,t4,16-1 + or t5,t5,t4 + + and t4,a0,0x04 # bit2 shift to bit32(LED2) -> bit0/high_reg. + srl t6,t4,2-0 + + and t4,a0,0x08 # bit3 shift to bit48(LED3) -> bit16/high_reg. + sll t4,t4,16-3 + or t6,t6,t4 + + and t4,a0,0x10 # bit4 shift to bit1(LED4) + srl t4,t4,4-1 + or t5,t5,t4 + + and t4,a0,0x20 # bit5 shift to bit17(LED5) + sll t4,t4,17-5 + or t5,t5,t4 + + and t4,a0,0x40 # bit6 shift to bit33(LED6) -> bit1/high_reg. + srl t4,t4,6-1 + or t6,t6,t4 + + and t4,a0,0x80 # bit7 shift to bit49(LED7) -> bit17/high_reg. + sll t4,t4,17-7 + or t6,t6,t4 + + lw a1,HalpLedAddress + lw t4,0(a1) + and t4,t4,PCI_TOWER_LED_MASK # led mask + or t4,t4,t5 # t5 -> low 32 bits + sw t4,0(a1) + jal KeFlushWriteBuffer + + lw a1,HalpLedAddress + lw t4,4(a1) + and t4,t4,PCI_TOWER_LED_MASK # led mask + or t4,t4,t6 # t6 -> high 32 bits + sw t4,4(a1) + jal KeFlushWriteBuffer + lw ra,CiRa(sp) // restore return address + addu sp,sp,CiFrameLength // deallocate stack frame + j ra + + .end HalpPciTowerDisplayLed +// +// end code for PCI 1tower +// diff --git a/private/ntos/nthals/halsnip/mips/x4misc.s b/private/ntos/nthals/halsnip/mips/x4misc.s new file mode 100644 index 000000000..c4c49fffd --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/x4misc.s @@ -0,0 +1,410 @@ +#if defined(R4000) +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/x4misc.s,v 1.4 1996/02/23 17:55:12 pierre Exp $") + +// TITLE("Misc R4000 Functions") +//++ +// +// Copyright (c) 1994 Siemens Nixdorf Informationssysteme AG +// +// Module Name: +// +// x4misc.s +// +// Abstract: +// +// This module implements some R4000 basic register access routines +// +// Environment: +// +// Kernel mode only. +// +//-- + +#include "halmips.h" +#include "SNIdef.h" +#define STATUS_DE 0x10000 // Disable Cache error ands ECC Errors bit +#define STATUS_IE 0x00001 // Interrupt Enable/Disable Bit +#define STATUS_KX 0x80 + +#define UNCACHED 0x2 +#define CACHABLE_NONCOHERENT 0x3 +#define CACHABLE_COHERENT_EXCLUSIVE 0x4 +#define CACHABLE_COHERENT_EXCLUSIVE_ON_WRITE 0x5 +#define CACHABLE_COHERENT_UPDATE_ON_WRITE 0x6 + + SBTTL("Get R4000 Status Register") +//++ +// +// ULONG +// HalpGetStatusRegister( +// VOID +// ) +// +// Routine Description: +// +// This function returns the current value of the status register +// +// +// Arguments: +// +// None. +// +// Return Value: +// +// The value of the Status register. +// +//-- + + LEAF_ENTRY(HalpGetStatusRegister) + + .set noreorder + .set noat + mfc0 v0,psr // get current PSR + nop // fill + nop + nop + nop + .set at + .set reorder + + j ra // return + + .end HalpGetStatusRegister + + SBTTL("Set R4000 Status Register") +//++ +// +// ULONG +// HalpSetStatusRegister( +// VOID +// ) +// +// Routine Description: +// +// This function sets the status register +// +// +// Arguments: +// +// None. +// +// Return Value: +// +// The previous value of the Status register. +// +//-- + + LEAF_ENTRY(HalpSetStatusRegister) + + .set noreorder + .set noat + mfc0 v0,psr // get current (old)PSR + nop // fill + nop + nop + nop + mtc0 a0,psr + .set at + .set reorder + + j ra // return + + .end HalpSetStatusRegister + + SBTTL("Get R4000 Cause Register") +//++ +// +// ULONG +// HalpGetCauseRegister( +// VOID +// ) +// +// Routine Description: +// +// This function returns the current value of the cause register +// +// +// Arguments: +// +// None. +// +// Return Value: +// +// The value of the cause register. +// +//-- + + LEAF_ENTRY(HalpGetCauseRegister) + + .set noreorder + .set noat + mfc0 v0,cause // get current cause + nop // fill + nop + nop + nop + .set at + .set reorder + + j ra // return + + .end HalpGetCauseRegister + + SBTTL("Set R4000 Cause Register") +//++ +// +// ULONG +// HalpSetCauseRegister( +// VOID +// ) +// +// Routine Description: +// +// This function sets the Cause register +// +// +// Arguments: +// +// None. +// +// Return Value: +// +// The previous value of the Cause register. +// +//-- + + LEAF_ENTRY(HalpSetCauseRegister) + + .set noreorder + .set noat + mfc0 v0,cause // get current (old)Cause + nop // fill + nop + nop + nop + mtc0 a0,cause + nop + nop + nop + .set at + .set reorder + + j ra // return + + .end HalpSetCauseRegister + + SBTTL("Get R4000 Config Register") +//++ +// +// ULONG +// HalpGetConfigRegister( +// VOID +// ) +// +// Routine Description: +// +// This function returns the current value of the Config register +// +// +// Arguments: +// +// None. +// +// Return Value: +// +// The value of the Config register. +// +//-- + + LEAF_ENTRY(HalpGetConfigRegister) + + .set noreorder + .set noat + mfc0 v0,config // get current Config + nop // fill + nop + nop + nop + .set at + .set reorder + + j ra // return + + .end HalpGetConfigRegister + + SBTTL("Set R4000 Config Register") +//++ +// +// ULONG +// HalpSetConfigRegister( +// VOID +// ) +// +// Routine Description: +// +// This function sets the R4000 Config register +// +// +// Arguments: +// +// None. +// +// Return Value: +// +// The previous value of the Config register. +// +//-- + + LEAF_ENTRY(HalpSetConfigRegister) + + .set noreorder + .set noat + mfc0 v0,config // get current (old)Config + nop // fill + nop + nop + nop + mtc0 a0,config + nop + nop + nop + nop + .set at + .set reorder + + j ra // return + + .end HalpSetConfigRegister +#endif + + +//++ +// +// ULONG +// HalpDisableInterrupts( +// VOID +// ) +// +// Routine Description: +// +// This function is called to disable interrupts after a PCI error interrupt, +// The machine is then stopped by a KeBugCheckEx(). +// This is indispensable for MATROX boards.... +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpDisableInterrupts) + +// +// Perform power management enabling. +// + + .set noreorder + mfc0 v0,psr // get current PSR + nop // fill + and v0, v0, ~(STATUS_IE) // disable Interrupts + mtc0 v0,psr // enable interrupts + + .set reorder +10: j ra + .end HalpDisableInterrupts + + +//++ +// +// ULONG +// HalpFindEccAddr( +// ULONG Addr, // from ECC Error Asic Register +// PVOID ErrStatusRegister, // register which indicates parity and Ecc error +// PVOID ErrStatusBits // bits which indicates errors in the previous register +// ) +// +// Routine Description: +// +// This function is called to find the real physical address where the error occurs, +// The Ecc Error Asic register contains the block address where the error address is. +// To get ride of memory above 0x10000000, we use 64bits addressing capabilities of +// the processor. +// To detect the faulty address, we read all the block of data, word by word... +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpFindEccAddr) + + + .set noreorder +// adjust addr to a cache line + lw t4,KiPcr + PcFirstLevelDcacheFillSize(zero) // get 1st fill size + subu t3,t4,1 + nor t3,t3,zero + and a0,a0,t3 + +// generate 64 bits addr + mfc0 t1,psr // get current PSR saved in t1 + nop // fill + and v0, t1, ~(STATUS_IE) // disable Interrupts +// or v0, v0, PSR_KX // 64 bits adressing in kernel + mtc0 v0,psr // enable interrupts + nop + nop + nop + + li t0,0x90000000 + .word 0x0008403c // dsll32 t0,t0,zero + or a0,a0,t0 // beginning KSEG1 addr in 64bits + daddu t0,a0,t4 // ending KSEG1 addr in 64bits + + or v0, v0, STATUS_KX // 64 bits adressing in kernel + mtc0 v0,psr + nop + nop + nop + +// reading loop +1: lw t8,0(a0) + nop + sync + + lw t8,0(a1) // PCI Error Status + nop + sync + + and t9,t8,a2 // test memory/ecc error bits + nop + beq t9,zero,2f + nop +// addr found + move v0,a0 + j 10f + nop +2: // addr not found => continue loop + daddiu a0,4 // word by word + bltu a0,t0,1b + nop + li v0,-1 // end of the loop - no addr found! + +10: + mtc0 t1,psr // enable interrupts + back to 32bits addressing + nop + nop + nop + .set reorder + j ra + .end HalpFindEccAddr + diff --git a/private/ntos/nthals/halsnip/mips/x4tb.s b/private/ntos/nthals/halsnip/mips/x4tb.s new file mode 100644 index 000000000..4120525f4 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/x4tb.s @@ -0,0 +1,110 @@ +#if defined(R4000) +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/x4tb.s,v 1.1 1995/07/20 16:04:27 flo Exp $") + +// TITLE("AllocateFree TB Entry") +//++ +// +// Copyright (c) 1992-1993 Microsoft Corporation +// +// Module Name: +// +// x4tb.s +// +// Abstract: +// +// This module implements allocates and frees fixed TB entries using the +// wired register. +// +// Environment: +// +// Kernel mode only. +// +//-- + +#include "halmips.h" + + SBTTL("Allocate Tb Entry") +//++ +// +// ULONG +// HalpAllocateTbEntry ( +// VOID +// ) +// +// Routine Description: +// +// This function allocates the TB entry specified by the wired register +// and increments the wired register. +// +// Arguments: +// +// None. +// +// Return Value: +// +// The index of the allocated TB entry. +// +//-- + + LEAF_ENTRY(HalpAllocateTbEntry) + + DISABLE_INTERRUPTS(t0) // disable interrupts + + .set noreorder + .set noat + mfc0 v0,wired // get contents of wired register + nop // fill + addu v1,v0,1 // allocate TB entry + mtc0 v1,wired // + .set at + .set reorder + + ENABLE_INTERRUPTS(t0) // enable interrupts + + j ra // return + + .end HalpAllocateTbEntry + + SBTTL("Free Tb Entry") +//++ +// +// VOID +// HalpFreeTbEntry ( +// VOID +// ) +// +// Routine Description: +// +// This function frees the TB entry specified by the wired register +// and decrements the wired register. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpFreeTbEntry) + + DISABLE_INTERRUPTS(t0) // disable interrupts + + .set noreorder + .set noat + mfc0 v0,wired // get contents of wired register + nop // fill + subu v1,v0,1 // free TB entry + mtc0 v1,wired // + .set at + .set reorder + + ENABLE_INTERRUPTS(t0) // enable interrupts + + j ra // return + + .end HalpFreeTbEntry + +#endif diff --git a/private/ntos/nthals/halsnip/mips/x86bios.c b/private/ntos/nthals/halsnip/mips/x86bios.c new file mode 100644 index 000000000..17cd688aa --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/x86bios.c @@ -0,0 +1,191 @@ +/*++ + +Copyright (c) 1994 Microsoft Corporation + +Module Name: + + x86bios.c + +Abstract: + + + This module implements the platform specific interface between a device + driver and the execution of x86 ROM bios code for the device. + +--*/ + +#include "halp.h" + +// +// Define global data. +// per default, we enable int10's but we do nort use them on our well known +// SNI graphic cards +// if we have an unknown card, we try to initialize it via the emulator and the card +// bios. if this fails, we disable int10 calls +// + +ULONG HalpX86BiosInitialized = FALSE; +ULONG HalpEnableInt10Calls = TRUE; + +BOOLEAN +HalCallBios ( + IN ULONG BiosCommand, + IN OUT PULONG Eax, + IN OUT PULONG Ebx, + IN OUT PULONG Ecx, + IN OUT PULONG Edx, + IN OUT PULONG Esi, + IN OUT PULONG Edi, + IN OUT PULONG Ebp + ) + +/*++ + +Routine Description: + + This function provides the platform specific interface between a device + driver and the execution of the x86 ROM bios code for the specified ROM + bios command. + +Arguments: + + BiosCommand - Supplies the ROM bios command to be emulated. + + Eax to Ebp - Supplies the x86 emulation context. + +Return Value: + + A value of TRUE is returned if the specified function is executed. + Otherwise, a value of FALSE is returned. + +--*/ + +{ + + XM86_CONTEXT Context; + + // + // If the X86 BIOS Emulator has not been initialized, then return FALSE. + // + + if (HalpX86BiosInitialized == FALSE) { + return FALSE; + } + + // + // If the Video Adapter initialization failed and an Int10 command is + // specified, then return FALSE. + // + + if (BiosCommand == 0x10){ + + if(HalpEnableInt10Calls == FALSE) { + return FALSE; + } + + // + // if Int10 commands are still enabled, Initialize the Card + // if it fails, disable Int10's + // this should make sense ... + // + + if (x86BiosInitializeAdapter(0xc0000, NULL, NULL, NULL) != XM_SUCCESS) { + HalpEnableInt10Calls = FALSE; + return FALSE; + } + } + + // + // Copy the x86 bios context and emulate the specified command. + // + + Context.Eax = *Eax; + Context.Ebx = *Ebx; + Context.Ecx = *Ecx; + Context.Edx = *Edx; + Context.Esi = *Esi; + Context.Edi = *Edi; + Context.Ebp = *Ebp; + if (x86BiosExecuteInterrupt((UCHAR)BiosCommand, &Context, NULL, NULL) != XM_SUCCESS) { + return FALSE; + } + + // + // Copy the x86 bios context and return TRUE. + // + + *Eax = Context.Eax; + *Ebx = Context.Ebx; + *Ecx = Context.Ecx; + *Edx = Context.Edx; + *Esi = Context.Esi; + *Edi = Context.Edi; + *Ebp = Context.Ebp; + return TRUE; +} + +VOID +HalpResetX86DisplayAdapter( + VOID + ) + +/*++ + +Routine Description: + + This function resets a display adapter using the x86 bios emulator. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + + XM86_CONTEXT Context; + + // + // Initialize the x86 bios context and make the INT 10 call to initialize + // the display adapter to 80x50 16 color text mode. + // this is done by two int10 calls like on an standard PC + // hopefully this works ... + // the sample code sets only 80x25 mode, but we want more !!! + // + + Context.Eax = 0x0003; // Function 0, Mode 3 + Context.Ebx = 0; + Context.Ecx = 0; + Context.Edx = 0; + Context.Esi = 0; + Context.Edi = 0; + Context.Ebp = 0; + + HalCallBios(0x10, + &Context.Eax, + &Context.Ebx, + &Context.Ecx, + &Context.Edx, + &Context.Esi, + &Context.Edi, + &Context.Ebp); + // + // Now change it to 80x50 8x8Font Mode + // + + Context.Eax = 0x1112; // use 8x8 font (causes 50 line mode) + Context.Ebx = 0; + + HalCallBios(0x10, + &Context.Eax, + &Context.Ebx, + &Context.Ecx, + &Context.Edx, + &Context.Esi, + &Context.Edi, + &Context.Ebp); +} diff --git a/private/ntos/nthals/halsnip/mips/xxcache.c b/private/ntos/nthals/halsnip/mips/xxcache.c new file mode 100644 index 000000000..69d72396f --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/xxcache.c @@ -0,0 +1,346 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/xxcache.c,v 1.4 1996/03/04 13:27:00 pierre Exp $") +/*++ + +Copyright (c) 1993-94 Siemens Nixdorf Informationssysteme AG + +Module Name: + + xxcache.c + +Abstract: + + + This module implements the functions necessesary to call the correct Cache routines + depending on Uni- or MultiProcessor machine typ. + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "halp.h" +#include "mpagent.h" +#include "xxcache.h" + +HalpProcessorType HalpProcessorId = UNKNOWN; + + + +// Desktop : processor may be R4600 or R4700 both of them with or without SC +// Minitower : processors may be R4700 with or without SC or R4400 + MPAgent (1 or 2) + +VOID +HalpProcessorConfig() +{ +ULONG Proc, reg; + + Proc = HalpProcIdentify(); + HalpMainBoard = (MotherBoardType) READ_REGISTER_UCHAR(0xbff0002a); + if (HalpMainBoard == M8150) HalpIsTowerPci = TRUE; + + switch (Proc) { + + case HalpR4600: + case HalpR4700: + if (PCR->SecondLevelDcacheFillSize) HalpProcessorId = ORIONSC; // ASIC driven SC + else HalpProcessorId = R4x00; + break; + + default: + // RM200 and RM300 use the same bit but use the opposite value to determine the new ASIC revision... + // ASIC rev 1.0 => cache replace memory (special area reserved by the firmware). + // ASIC rev >= 1.1 => cache replace with the ASIC register value. + if (HalpMainBoard == DesktopPCI) { + UCHAR tmp; + tmp = READ_REGISTER_UCHAR(PCI_MSR_ADDR); + if (tmp & PCI_MSR_REV_ASIC) HalpMpaCacheReplace = RM300_RESERVED | KSEG0_BASE; // rev 1.0 + else HalpMpaCacheReplace = MPAGENT_RESERVED | KSEG0_BASE; // rev 1.1 + } else { + if (HalpMainBoard == MinitowerPCI) { + UCHAR tmp; + tmp = READ_REGISTER_UCHAR(PCI_MSR_ADDR); + if (tmp & PCI_MSR_REV_ASIC) HalpMpaCacheReplace = MPAGENT_RESERVED | KSEG0_BASE; // rev 1.1 + else HalpMpaCacheReplace = RM300_RESERVED | KSEG0_BASE; // rev 1.0 + } else HalpMpaCacheReplace = MPAGENT_RESERVED | KSEG0_BASE; // RM400 all ASIC + } + + HalpProcessorId = MPAGENT; // R4x00 always with MPAgent on the PCI range. + + if (HalpMpaCacheReplace == MPAGENT_RESERVED | KSEG0_BASE) { + reg = ((MPAGENT_RESERVED & // put the reserved physical address (4Mb long) + MPA_OP_ADDR_MASK) | + MPA_OP_ENABLE); // enable the operator + } else { + reg = 0; + } + + WRITE_REGISTER_ULONG(&(mpagent->mem_operator), reg); // for all procs (done for proc 0 in xxcache) + + } + + return; +} + +VOID +HalFlushDcachePage( + IN PVOID Color, + IN ULONG PageFrame, + IN ULONG Length + ) +{ + + switch (HalpProcessorId) { + + case MPAGENT: + + HalpFlushDcachePageMulti( + Color, + PageFrame, + Length + ); + break; + + case ORIONSC: + + HalSweepDcacheRange( + Color, + Length + ); + HalpFlushDcachePageOrion( + Color, + PageFrame, + Length + ); + break; + + case R4x00: + + HalpFlushDcachePageUni( + Color, + PageFrame, + Length + ); + break; + + case UNKNOWN: + + HalpProcessorConfig(); + HalFlushDcachePage(Color, PageFrame, Length); + + } + +} + +VOID +HalPurgeDcachePage ( + IN PVOID Color, + IN ULONG PageFrame, + IN ULONG Length + ) +{ + + switch (HalpProcessorId) { + + case MPAGENT: + + HalpFlushDcachePageMulti( + Color, + PageFrame, + Length + ); + break; + + case ORIONSC: + + HalSweepDcacheRange( + Color, + Length + ); + HalpFlushDcachePageOrion( + Color, + PageFrame, + Length + ); + break; + + case R4x00: + + HalpPurgeDcachePageUni( + Color, + PageFrame, + Length + ); + break; + + case UNKNOWN: + + HalpProcessorConfig(); + HalPurgeDcachePage(Color, PageFrame, Length); + + } + +} + +VOID +HalPurgeIcachePage( + IN PVOID Color, + IN ULONG PageFrame, + IN ULONG Length + ) +{ + + switch (HalpProcessorId) { + + case MPAGENT: + + HalpPurgeIcachePageMulti( + Color, + PageFrame, + Length + ); + break; + + case ORIONSC: + + HalSweepIcacheRange( + Color, + Length + ); + HalpPurgeIcachePageOrion( + Color, + PageFrame, + Length + ); + break; + + case R4x00: + + HalpPurgeIcachePageUni( + Color, + PageFrame, + Length + ); + break; + + case UNKNOWN: + + HalpProcessorConfig(); + HalPurgeIcachePage(Color, PageFrame, Length); + + } + +} + +VOID +HalSweepDcache( + VOID + ) +{ + + switch (HalpProcessorId) { + + case MPAGENT: + + HalpSweepDcacheMulti(); + break; + + case ORIONSC: + + HalpSweepDcacheOrion(); + break; + + case R4x00: + + HalpSweepDcacheUni(); + break; + + case UNKNOWN: + + HalpProcessorConfig(); + HalSweepDcache(); + + } + +} + +VOID +HalSweepIcache ( + VOID + ) +{ + + switch (HalpProcessorId) { + + case MPAGENT: + + HalpSweepIcacheMulti(); + break; + + case ORIONSC: + + HalpSweepIcacheOrion(); + break; + + case R4x00: + + HalpSweepIcacheUni(); + break; + + case UNKNOWN: + + HalpProcessorConfig(); + HalSweepIcache(); + + } + +} + +VOID +HalZeroPage ( + IN PVOID NewColor, + IN PVOID OldColor, + IN ULONG PageFrame + ) +{ + + switch (HalpProcessorId) { + + case MPAGENT: + + HalpZeroPageMulti( + NewColor, + OldColor, + PageFrame + ); + break; + + case ORIONSC: + + HalpZeroPageOrion( + NewColor, + OldColor, + PageFrame + ); + break; + + case R4x00: + + HalpZeroPageUni( + NewColor, + OldColor, + PageFrame + ); + break; + + case UNKNOWN: + + HalpProcessorConfig(); + HalZeroPage(NewColor, OldColor, PageFrame); + + } + +} + diff --git a/private/ntos/nthals/halsnip/mips/xxcache.h b/private/ntos/nthals/halsnip/mips/xxcache.h new file mode 100644 index 000000000..6bc20b155 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/xxcache.h @@ -0,0 +1,30 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/xxcache.h,v 1.2 1996/03/04 13:27:16 pierre Exp $") + +// +// Prototypes for private cache functions +// they match the ones defined for the HAL ... +// + +VOID HalpZeroPageOrion(IN PVOID NewColor, IN PVOID OldColor, IN ULONG PageFrame); +VOID HalpZeroPageMulti(IN PVOID NewColor, IN PVOID OldColor, IN ULONG PageFrame); +VOID HalpZeroPageUni(IN PVOID NewColor, IN PVOID OldColor, IN ULONG PageFrame); + +VOID HalpSweepIcacheOrion(VOID); +VOID HalpSweepIcacheMulti(VOID); +VOID HalpSweepIcacheUni(VOID); + +VOID HalpSweepDcacheOrion(VOID); +VOID HalpSweepDcacheMulti(VOID); +VOID HalpSweepDcacheUni(VOID); + +VOID HalpPurgeIcachePageOrion(IN PVOID Color, IN ULONG PageFrame, IN ULONG Length); +VOID HalpPurgeIcachePageMulti(IN PVOID Color, IN ULONG PageFrame, IN ULONG Length); +VOID HalpPurgeIcachePageUni(IN PVOID Color, IN ULONG PageFrame, IN ULONG Length); + +VOID HalpPurgeDcachePageUni(IN PVOID Color, IN ULONG PageFrame, IN ULONG Length); + +VOID HalpFlushDcachePageOrion(IN PVOID Color, IN ULONG PageFrame, IN ULONG Length); +VOID HalpFlushDcachePageMulti(IN PVOID Color, IN ULONG PageFrame, IN ULONG Length); +VOID HalpFlushDcachePageUni(IN PVOID Color, IN ULONG PageFrame, IN ULONG Length); + + diff --git a/private/ntos/nthals/halsnip/mips/xxcalstl.c b/private/ntos/nthals/halsnip/mips/xxcalstl.c new file mode 100644 index 000000000..1eb6e4c17 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/xxcalstl.c @@ -0,0 +1,278 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/xxcalstl.c,v 1.4 1996/03/04 13:27:51 pierre Exp $") +/*++ + +Copyright (c) 1991 - 1994 Microsoft Corporation + +Module Name: + + xxcalstl.c + +Abstract: + + + This module implements the calibration of the stall execution HAL + service, computes the count rate for the profile clock, and connects + the clock and profile interrupts for a MIPS R3000 or R4000 system. + +Environment: + + Kernel mode only. + +--*/ + +#include "halp.h" +#include "stdio.h" + +#if DBG +UCHAR HalpBuffer[128]; +#endif +// +// Put all code for HAL initialization in the INIT section. It will be +// deallocated by memory management when phase 1 initialization is +// completed. +// + +#if defined(ALLOC_PRAGMA) + +#pragma alloc_text(INIT, HalpCalibrateStall) +#pragma alloc_text(INIT, HalpStallInterrupt) + +#endif + +// +// Define global data used to calibrate and stall processor execution. +// + + +ULONG HalpProfileCountRate; +ULONG volatile HalpStallEnd; +ULONG HalpStallScaleFactor; +ULONG volatile HalpStallStart; + +BOOLEAN +HalpCalibrateStall ( + VOID + ) + +/*++ + +Routine Description: + + This function calibrates the stall execution HAL service and connects + the clock and profile interrupts to the appropriate NT service routines. + +Arguments: + + None. + +Return Value: + + A value of TRUE is returned if the calibration is successfully + completed. Otherwise a value of FALSE is returned. + +--*/ + +{ + + ULONG Index; + KIRQL OldIrql; + + // + // Use a range of scale factors from 50ns down to 10ns assuming a + // five instruction stall loop. + // + + for (Index = 200; Index > 0; Index -= 10) { + + // + // Disable all interrupts and establish calibration parameters. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + // + // Set the scale factor, stall count, starting stall count, and + // ending stall count values. + // + + PCR->StallScaleFactor = 4000 / (Index * 5); + PCR->StallExecutionCount = 0; + HalpStallStart = 0; + HalpStallEnd = 0; + + // + // Enable interrupts and stall execution. + // + + KeLowerIrql(OldIrql); + + // + // Stall execution for (MAXIMUM_INCREMENT / 10) * 4 us. + // + + KeStallExecutionProcessor((MAXIMUM_INCREMENT / 10) * 4); + + // + // If both the starting and ending stall counts have been captured, + // then break out of loop. + // + + if ((HalpStallStart != 0) && (HalpStallEnd != 0)) { + break; + } + + } + + if (Index == 0) { + HalDisplayString("ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»\n"); + HalDisplayString("ºWARNING: Cannot compute stall factor º\n"); + HalDisplayString("ºWARNING: Using default value (250 Mhz) º\n"); + HalDisplayString("ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ\n"); + HalpStallScaleFactor = 0x20; + HalpProfileCountRate = 125*1000000; + } + else { + // + // Compute the profile interrupt rate. + // + + HalpProfileCountRate = + HalpProfileCountRate * ((1000 * 1000 * 10) / MAXIMUM_INCREMENT); + + // + // Compute the stall execution scale factor. + // + + HalpStallScaleFactor = (HalpStallEnd - HalpStallStart + + ((MAXIMUM_INCREMENT / 10) - 1)) / (MAXIMUM_INCREMENT / 10); + + if (HalpStallScaleFactor <= 0) { + HalpStallScaleFactor = 1; + } + } + + PCR->StallScaleFactor = HalpStallScaleFactor; + + // + // Set the time increment value and connect the real clock interrupt + // routine. + // + + PCR->InterruptRoutine[CLOCK2_LEVEL] = (PKINTERRUPT_ROUTINE) HalpClockInterrupt; + + // + // Write the compare register and clear the count register, and + // connect the profile interrupt if profiling is done via count/compare interrupt. + // + + HalpWriteCompareRegisterAndClear(DEFAULT_PROFILE_COUNT); + PCR->InterruptRoutine[PROFILE_LEVEL] = (PKINTERRUPT_ROUTINE) HalpProfileInterrupt; + +#if DBG + sprintf(HalpBuffer,"HalpCalibrateStall : CPU frequency is %d MHz, StallFactor is %d\n", (HalpProfileCountRate/1000000)*2, HalpStallScaleFactor); + HalDisplayString(HalpBuffer); +#endif + + return TRUE; +} + +VOID +KeStallExecutionProcessor ( + IN ULONG MicroSeconds + ) + +/*++ + +Routine Description: + + This function stalls execution of the current processor for the specified + number of microseconds. + +Arguments: + + MicroSeconds - Supplies the number of microseconds that execution is to + be stalled. + +Return Value: + + None. + +--*/ + +{ + + ULONG Index; + + + // + // Use the stall scale factor to determine the number of iterations + // the wait loop must be executed to stall the processor for the + // specified number of microseconds. + // + + Index = MicroSeconds * PCR->StallScaleFactor; + do { + PCR->StallExecutionCount += 1; + Index -= 1; + } while (Index > 0); + + return; +} + + +VOID +HalpStallInterrupt ( + VOID + ) + +/*++ + +Routine Description: + + This function serves as the stall calibration interrupt service + routine. It is executed in response to system clock interrupts + during the initialization of the HAL layer. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + + // + // If this is the very first interrupt, then wait for the second + // interrupt before starting the timing interval. Else, if this + // the second interrupt, then capture the starting stall count + // and clear the count register on R4000 processors. Else, if this + // is the third interrupt, then capture the ending stall count and + // the ending count register on R4000 processors. Else, if this is + // the fourth or subsequent interrupt, then simply dismiss it. + // + + if ((HalpStallStart == 0) && (HalpStallEnd == 0)) { + HalpStallEnd = 1; + + } else if ((HalpStallStart == 0) && (HalpStallEnd != 0)) { + HalpStallStart = PCR->StallExecutionCount; + + HalpStallEnd = 0; + + HalpWriteCompareRegisterAndClear(0); + + } else if ((HalpStallStart != 0) && (HalpStallEnd == 0)) { + HalpStallEnd = PCR->StallExecutionCount; + + HalpProfileCountRate = HalpWriteCompareRegisterAndClear(0); + + } + + + return; +} + diff --git a/private/ntos/nthals/halsnip/mips/xxclock.c b/private/ntos/nthals/halsnip/mips/xxclock.c new file mode 100644 index 000000000..c9da66a5c --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/xxclock.c @@ -0,0 +1,277 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/xxclock.c,v 1.3 1995/11/02 11:04:33 flo Exp $") + +/*++ + +Copyright (c) 1993-94 Siemens Nixdorf Informationssysteme AG +Copyright (c) 1985-94 Microsoft Corporation + +Module Name: + + xxclock.c + +Abstract: + + + This module implements the function necesssary to change the clock + interrupt rate. + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "halp.h" +#include "eisa.h" +#include "i82C54.h" + + +// +// Define global data used to communicate new clock rates to the clock +// interrupt service routine. +// + +ULONG HalpCurrentTimeIncrement; +ULONG HalpNextTimeIncrement; +ULONG HalpNewTimeIncrement; + +ULONG +HalSetTimeIncrement ( + IN ULONG DesiredIncrement + ) + +/*++ + +Routine Description: + + This function is called to set the clock interrupt rate to the frequency + required by the specified time increment value. + + N.B. This function is only executed on the processor that keeps the + system time. + +Arguments: + + DesiredIncrement - Supplies desired number of 100ns units between clock + interrupts. + +Return Value: + + The actual time increment in 100ns units. + +--*/ + +{ + + ULONG NewTimeIncrement; + KIRQL OldIrql; + + if (DesiredIncrement < MINIMUM_INCREMENT) { + DesiredIncrement = MINIMUM_INCREMENT; + } + if (DesiredIncrement > MAXIMUM_INCREMENT) { + DesiredIncrement = MAXIMUM_INCREMENT; + } + + // + // Raise IRQL to the highest level, set the new clock interrupt + // parameters, lower IRQl, and return the new time increment value. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + NewTimeIncrement = DesiredIncrement / MINIMUM_INCREMENT; + NewTimeIncrement = NewTimeIncrement * MINIMUM_INCREMENT; + HalpNewTimeIncrement = NewTimeIncrement ; + KeLowerIrql(OldIrql); + return NewTimeIncrement; +} + +VOID +HalpProgramIntervalTimer ( + IN ULONG Interval + ) +/*++ + +Routine Description: + + This function is called to program the System clock according to the frequency + required by the specified time increment value. + + N.B. this information was found in the jenson (ALPHA) HAL + also valid for MIPS computer ??? + + There are four different rates that are used under NT + (see page 9-8 of KN121 System Module Programmer's Reference) + + .976562 ms + 1.953125 ms + 3.90625 ms + 7.8125 ms + + +Arguments: + + Interval - Supplies desired number of 100ns units between clock + interrupts. + +Return Value: + + none. + +--*/ +{ + PEISA_CONTROL controlBase = (PEISA_CONTROL)HalpOnboardControlBase; + ULONG Count; + TIMER_CONTROL timerControl; + KIRQL OldIrql; + + // + // Raise IRQL to the highest level, set the new clock interrupt + // parameters, lower IRQl, and return the new time increment value. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + // + // Start the system clock to interrupt at the desired interval. + // + // + + timerControl.BcdMode = 0; + timerControl.Mode = TM_SQUARE_WAVE; + timerControl.SelectByte = SB_LSB_THEN_MSB; + timerControl.SelectCounter = SELECT_COUNTER_0; + + // + // use timer in the onboard PC core + // + + Count = TIMER_CLOCK_IN / ( 10000000 / Interval ); + + WRITE_REGISTER_UCHAR(&controlBase->CommandMode1, *((PUCHAR) &timerControl)); + + // + // Set the system clock timer to the correct frequency. + // + + WRITE_REGISTER_UCHAR(&controlBase->Timer1, (UCHAR)Count); + WRITE_REGISTER_UCHAR(&controlBase->Timer1, (UCHAR)(Count >> 8)); + + KeLowerIrql(OldIrql); +} + + +VOID +HalpProgramExtraTimer ( + IN ULONG Interval + ) +/*++ + +Routine Description: + + This function is called to program the second clock generator in a multiprocessor System + according to the frequency required by the specified Interval value (in 100ns units). + + +Arguments: + + Interval - Supplies desired number of 100ns units between clock + interrupts. + +Return Value: + + none. + +--*/ +{ + + volatile PLOCAL_8254 pt = (PLOCAL_8254) PCI_EXTRA_TIMER_ADDR; + ULONG Count; + TIMER_CONTROL timerControl; + KIRQL OldIrql; + + // + // Raise IRQL to the highest level, set the new clock interrupt + // parameters, lower IRQl, and return the new time increment value. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + // + // Start the system clock to interrupt at the desired interval. + // + // + + timerControl.BcdMode = 0; + timerControl.Mode = TM_SQUARE_WAVE; + timerControl.SelectByte = SB_LSB_THEN_MSB; + timerControl.SelectCounter = SELECT_COUNTER_0; + + Count = EXTRA_TIMER_CLOCK_IN / (PRE_COUNT * 10000000 / Interval ); + + WRITE_REGISTER_UCHAR( &pt->control, *((PUCHAR) &timerControl)); + WRITE_REGISTER_UCHAR(&(pt->counter0), (UCHAR)Count); + WRITE_REGISTER_UCHAR(&(pt->counter0), (UCHAR)(Count >> 8)); + + timerControl.BcdMode = 0; + timerControl.Mode = TM_RATE_GENERATOR; + timerControl.SelectByte = SB_LSB_THEN_MSB; + timerControl.SelectCounter = SELECT_COUNTER_2; + + // the output of counter 2 is hardwired as input to counter 0/1 + // so we use it as a pre-counter + + WRITE_REGISTER_UCHAR( &pt->control, *((PUCHAR) &timerControl)); + WRITE_REGISTER_UCHAR(&(pt->counter2), (UCHAR)PRE_COUNT); + WRITE_REGISTER_UCHAR(&(pt->counter2), (UCHAR)(PRE_COUNT >>8)); + + KeLowerIrql(OldIrql); + +} + + +VOID +HalpProgramExtraTimerPciT ( + IN ULONG Interval + ) +/*++ + +Routine Description: + + This function is called to program the second clock generator in PCI tower + according to the frequency required by the specified Interval value (in 100ns units). + + +Arguments: + + Interval - Supplies desired number of 100ns units between clock + interrupts. + +Return Value: + + none. + +--*/ +{ + + KIRQL OldIrql; + + //Stop the timer + WRITE_REGISTER_UCHAR(PCI_TOWER_TIMER_CMD_REG,0); + + //Reset Timer-Count Register + WRITE_REGISTER_UCHAR(PCI_TOWER_TIMER_COUNT_REG,0); + + //Set Timer-Value Register in ms + WRITE_REGISTER_UCHAR(PCI_TOWER_TIMER_VALUE_REG,(UCHAR)(Interval/10000)); + + //Start Timer + WRITE_REGISTER_UCHAR(PCI_TOWER_TIMER_CMD_REG,1); + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + KeLowerIrql(OldIrql); + +} diff --git a/private/ntos/nthals/halsnip/mips/xxerror.c b/private/ntos/nthals/halsnip/mips/xxerror.c new file mode 100644 index 000000000..f55c9dd81 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/xxerror.c @@ -0,0 +1,293 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/xxerror.c,v 1.3 1996/05/15 08:13:24 pierre Exp $") +/*-- + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + xxerror.c + +Abstract: + + + This module implements the management of errors (KeBugCheckEx, HalpBusError) + +Environment: + + Kernel mode only. + + +--*/ + +#include "halp.h" +#include "string.h" + +// +// Messages for CacheError routine +// + +UCHAR HalpErrCacheMsg[] = "\nCACHE ERROR\n"; +UCHAR HalpParityErrMsg[] = "\nPARITY ERROR\n"; +UCHAR HalpAddrErrMsg[] = "Address in error not found\n"; +ULONG HalpCacheErrFirst = 0; + +ULONG HalpKeBugCheck0; +ULONG HalpKeBugCheck1; +ULONG HalpKeBugCheck2; +ULONG HalpKeBugCheck3; +ULONG HalpKeBugCheck4; + +VOID +HalpBugCheckCallback ( + IN PVOID Buffer, + IN ULONG Length + ); + +// +// Define bug check information buffer and callback record. +// + +HALP_BUGCHECK_BUFFER HalpBugCheckBuffer; + +KBUGCHECK_CALLBACK_RECORD HalpCallbackRecord; + +UCHAR HalpComponentId[] = "hal.dll"; + +// +// Define BugCheck Number and BugCheck Additional Message +// + +ULONG HalpBugCheckNumber = (ULONG)(-1); + +PUCHAR HalpBugCheckMessage[] = { +"MP_Agent fatal error\n", // #0 +"ASIC PCI TRANSFER ERROR\n", // #1 +"ECC SINGLE ERROR COUNTER OVERFLOW\n", // #2 +"UNCORRECTABLE ECC ERROR\n", // #3 +"PCI TIMEOUT ERROR\n", // #4 +"MP_BUS PARITY ERROR\n", // #5 +"MP_BUS REGISTER SIZE ERROR\n", // #6 +"MEMORY ADDRESS ERROR\n", // #7 +"MEMORY SLOT ERROR\n", // #8 +"MEMORY CONFIG ERROR\n", // #9 +"PCI INITIATOR INTERRUPT ERROR\n", // #10 +"PCI TARGET INTERRUPT ERROR\n", // #11 +"PCI PARITY INTERRUPT ERROR\n", // #12 +"MULTIPLE PCI INITIATOR ERROR\n", // #13 +"MULTIPLE PCI TARGET ERROR\n", // #14 +"MULTIPLE PCI PARITY ERROR\n", // #15 +"DATA_BUS_ERROR\n", // #16 +"INSTRUCTION_BUS_ERROR\n", // #17 +"PARITY ERROR\n", // #18 +"CACHE ERROR\n" // #19 +}; + +VOID +HalpBugCheckCallback ( + IN PVOID Buffer, + IN ULONG Length + ) + +/*++ + +Routine Description: + + This function is called when a bug check occurs. Its function is + to dump the state of the memory error registers into a bug check + buffer. + +Arguments: + + Buffer - Supplies a pointer to the bug check buffer. + + Length - Supplies the length of the bug check buffer in bytes. + +Return Value: + + None. + +--*/ + +{ + + PHALP_BUGCHECK_BUFFER DumpBuffer; + PUCHAR p,q; + + if (HalpBugCheckNumber == -1) return; // that is not a HAL bugcheck ... + + // + // Capture the failed memory address and diagnostic registers. + // + + DumpBuffer = (PHALP_BUGCHECK_BUFFER)Buffer; + + DumpBuffer->Par0 = HalpKeBugCheck0; + DumpBuffer->Par1 = HalpKeBugCheck1; + DumpBuffer->Par2 = HalpKeBugCheck2; + DumpBuffer->Par3 = HalpKeBugCheck3; + DumpBuffer->Par4 = HalpKeBugCheck4; + DumpBuffer->MainBoard = HalpMainBoard; + p = DumpBuffer->TEXT;q = HalpBugCheckMessage[HalpBugCheckNumber]; + while (*q) *p++ = *q++; + return; +} + + +BOOLEAN +HalpBusError ( + IN PEXCEPTION_RECORD ExceptionRecord, + IN PKEXCEPTION_FRAME ExceptionFrame, + IN PKTRAP_FRAME TrapFrame, + IN PVOID VirtualAddress, + IN PHYSICAL_ADDRESS PhysicalAddress + ) + +/*++ + +Routine Description: + + This function provides the default bus error handling routine for NT. + + N.B. There is no return from this routine. + +Arguments: + + ExceptionRecord - Supplies a pointer to an exception record. + + ExceptionFrame - Supplies a pointer to an exception frame. + + TrapFrame - Supplies a pointer to a trap frame. + + VirtualAddress - Supplies the virtual address of the bus error. + + PhysicalAddress - Supplies the physical address of the bus error. + +Return Value: + + None. + +--*/ + +{ + + KIRQL OldIrql; + UCHAR IntSource; + UCHAR MaStatus; + ULONG Itpend; + + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + KiAcquireSpinLock(&HalpInterruptLock); + + + + if (HalpIsTowerPci){ + // stop the extra-timer + + WRITE_REGISTER_UCHAR(PCI_TOWER_TIMER_CMD_REG,0); + + + HalpPciTowerInt3Dispatch(&HalpInt3Interrupt,(PVOID)PCI_TOWER_INTERRUPT_SOURCE_REGISTER); + }else{ + + IntSource = READ_REGISTER_UCHAR(PCI_INTERRUPT_SOURCE_REGISTER); + + IntSource ^= PCI_INTERRUPT_MASK; // XOR the low active bits with 1 gives 1 + // and XOR the high active with 0 gives 1 + if ( IntSource & PCI_INT2_MASK) { + + MaStatus = READ_REGISTER_UCHAR(PCI_MSR_ADDR); + if (HalpMainBoard == DesktopPCI) { + MaStatus ^= PCI_MSR_MASK_D; + } else { + MaStatus ^= PCI_MSR_MASK_MT; + }//(HalpMainBoard == DesktopPCI) + + // + // look for an ASIC interrupt + // + + if ( MaStatus & PCI_MSR_ASIC_MASK){ + + Itpend = READ_REGISTER_ULONG(PCI_ITPEND_REGISTER); + + if ( Itpend & (PCI_ASIC_ECCERROR | PCI_ASIC_TRPERROR)) { + + ULONG AsicErrAddr, ErrAddr, Syndrome, ErrStatus; + + ErrAddr = READ_REGISTER_ULONG(PCI_ERRADDR_REGISTER); + Syndrome = READ_REGISTER_ULONG(PCI_SYNDROME_REGISTER); + ErrStatus = READ_REGISTER_ULONG(PCI_ERRSTATUS_REGISTER); + + if (ErrStatus & PCI_MEMSTAT_PARERR) { + // Parity error (PCI_ASIC <-> CPU) +#if DBG + DebugPrint(("pci_memory_error : errstatus=0x%x Add error=0x%x syndrome=0x%x \n", + ErrStatus,ErrAddr,Syndrome)); + DbgBreakPoint(); +#else + HalpDisableInterrupts(); // for the MATROX boards... + HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode + HalDisplayString("\n"); + HalpClearVGADisplay(); + HalpBugCheckNumber = 1; + HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "PARITY ERROR\n" + HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,ErrAddr,HalpComputeNum((UCHAR *)ErrAddr),Syndrome); +#endif + }//if (ErrStatus & PCI_MEMSTAT_PARERR) + + + + if (ErrStatus & PCI_MEMSTAT_ECCERR) { + + AsicErrAddr &= 0xfffffff8; + ErrAddr = HalpFindEccAddr(AsicErrAddr,(PVOID)PCI_ERRSTATUS_REGISTER,(PVOID)PCI_MEMSTAT_ECCERR); + if (ErrAddr == -1) ErrAddr = AsicErrAddr; + +#if DBG + // UNIX => PANIC + DebugPrint(("pci_ecc_error : errstatus=0x%x Add error=0x%x syndrome=0x%x \n", + ErrStatus,ErrAddr,Syndrome)); + DbgBreakPoint(); +#else + HalpDisableInterrupts(); // for the MATROX boards... + HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode + HalDisplayString("\n"); + HalpClearVGADisplay(); + HalpBugCheckNumber = 3; + HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "UNCORRECTABLE ECC ERROR\n" + HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,ErrAddr,HalpComputeNum((UCHAR *)ErrAddr),Syndrome); +#endif + } //if (ErrStatus & PCI_MEMSTAT_ECCERR) + } //if ( Itpend & (PCI_ASIC_ECCERROR | PCI_ASIC_TRPERROR)) + + + }//if ( MaStatus & PCI_MSR_ASIC_MASK) + + }//if ( IntSource & PCI_INT2_MASK) + }//if (HalpIsTowerPci) + + // arrive here if no interruption found + HalpDisableInterrupts(); // for the MATROX boards... + HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode + HalDisplayString("\n"); + HalpClearVGADisplay(); + if (( ExceptionRecord->ExceptionCode & DATA_BUS_ERROR ) == DATA_BUS_ERROR) { + HalpBugCheckNumber = 16; + HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "DATA_BUS_ERROR\n" + } else { + HalpBugCheckNumber = 17; + HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "INSTRUCTION_BUS_ERROR\n" + } + + HalpKeBugCheckEx(ExceptionRecord->ExceptionCode , + HalpBugCheckNumber, + (ULONG)VirtualAddress, + (ULONG)PhysicalAddress.LowPart, + 0); + + KiReleaseSpinLock(&HalpInterruptLock); + KeLowerIrql(OldIrql); + +return FALSE; +} diff --git a/private/ntos/nthals/halsnip/mips/xxidle.s b/private/ntos/nthals/halsnip/mips/xxidle.s new file mode 100644 index 000000000..97c9a8d6d --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/xxidle.s @@ -0,0 +1,79 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/xxidle.s,v 1.3 1995/11/02 11:04:33 flo Exp $") +// TITLE("Processor Idle") +//++ +// +// Copyright (c) 1994 Microsoft Corporation +// +// Module Name: +// +// xxidle.s +// +// Abstract: +// +// This module implements system platform dependent power management +// support. +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// +//-- + +#include "halmips.h" + + SBTTL("Processor Idle") +//++ +// +// VOID +// HalProcessorIdle( +// VOID +// ) +// +// Routine Description: +// +// This function is called when the current processor is idle with +// interrupts disabled. There is no thread active and there are no +// DPCs to process. Therefore, power can be switched to a standby +// mode until the the next interrupt occurs on the current processor. +// +// N.B. This routine is entered with IE in PSR clear. This routine +// must do any power management enabling necessary, set the IE +// bit in PSR, then either return or wait for an interrupt. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalProcessorIdle) + +// +// Perform power management enabling. +// + + .set noreorder + .set noat + mfc0 v0,psr // get current PSR + nop // fill + or v0,v0,1 << PSR_IE // set interrupt enable. + mtc0 v0,psr // enable interrupts + + .set at + .set reorder + +// +// Wait for an interrupt if supported. +// + li a0,0x01 + j HalpCheckSpuriousInt // return + +10: j ra + .end HalProcessorIdle + diff --git a/private/ntos/nthals/halsnip/mips/xxinithl.c b/private/ntos/nthals/halsnip/mips/xxinithl.c new file mode 100644 index 000000000..61e462bb0 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/xxinithl.c @@ -0,0 +1,695 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/xxinithl.c,v 1.13 1996/05/15 08:14:04 pierre Exp $") +/*-- + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + xxinithl.c + +Abstract: + + + This module implements the initialization of the system dependent + functions that define the Hardware Architecture Layer (HAL) for a + MIPS R3000 or R4000 system. + +Environment: + + Kernel mode only. + + +--*/ + +#include "halp.h" +#include "eisa.h" +#include "string.h" +#include "mpagent.h" +#include "snipbus.h" + +ULONG HalpLedRegister; +PUCHAR HalpLedAddress = (PUCHAR)PCI_LED_ADDR;; +ULONG HalpMapBufferSize; +PHYSICAL_ADDRESS HalpMapBufferPhysicalAddress; +BOOLEAN LessThan16Mb; +BOOLEAN HalpEisaDma; +MotherBoardType HalpMainBoard; + +// MultiProcessor machine has a MpAgent per processor +// Values of HalpIsMulti are : +// 0 : 1 processor +// 2 : 2 processors +// n : n processors + +UCHAR HalpIsMulti = 0; + +BOOLEAN HalpCountCompareInterrupt = FALSE; +BOOLEAN HalpIsTowerPci = FALSE; +ULONG HalpMpaCacheReplace = RM300_RESERVED | KSEG0_BASE; // address to be used for cache replace operation. +ULONG HalpTwoWayBit; // size of one set for associative cache R5000-R4600-R4700 + +// +// Define global spin locks used to synchronize various HAL operations. +// + +KSPIN_LOCK HalpBeepLock; +KSPIN_LOCK HalpDisplayAdapterLock; +KSPIN_LOCK HalpSystemInterruptLock; +KSPIN_LOCK HalpInterruptLock; +KSPIN_LOCK HalpMemoryBufferLock; + +extern VOID HalpParseLoaderBlock(IN PLOADER_PARAMETER_BLOCK LoaderBlock) ; +BOOLEAN HalPCIRegistryInitialized = FALSE; +BOOLEAN HalpESC_SB; + +extern UCHAR +HalpRevIdESC( + VOID + ); + +BOOLEAN +HalpBusError ( + IN PEXCEPTION_RECORD ExceptionRecord, + IN PKEXCEPTION_FRAME ExceptionFrame, + IN PKTRAP_FRAME TrapFrame, + IN PVOID VirtualAddress, + IN PHYSICAL_ADDRESS PhysicalAddress + ); + +// +// Put all code for HAL initialization in the INIT section. It will be +// deallocated by memory management when phase 1 initialization is +// completed. +// + +#if defined(ALLOC_PRAGMA) + +#pragma alloc_text(INIT, HalInitSystem) +#pragma alloc_text(INIT, HalInitializeProcessor) +#pragma alloc_text(INIT, HalStartNextProcessor) +#pragma alloc_text(INIT, HalpDisplayCopyRight) + +#endif + + +BOOLEAN +HalInitSystem ( + IN ULONG Phase, + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ) + +/*++ + +Routine Description: + + This function initializes the Hardware Architecture Layer (HAL) for a + MIPS R3000 or R4000 system. + +Arguments: + + Phase - Supplies the initialization phase (zero or one). + + LoaderBlock - Supplies a pointer to a loader parameter block. + +Return Value: + + A value of TRUE is returned is the initialization was successfully + complete. Otherwise a value of FALSE is returend. + +--*/ + +{ + PMEMORY_ALLOCATION_DESCRIPTOR Descriptor; + PLIST_ENTRY NextMd; + PKPRCB Prcb; + ULONG BuildType = 0; + PRESTART_BLOCK NextRestartBlock; + ULONG PciData; + + Prcb = PCR->Prcb; + + PCR->DataBusError = HalpBusError; + PCR->InstructionBusError = HalpBusError; + + if ((Phase == 0) || (Prcb->Number != 0)) { + + // + // Phase 0 initialization. + // + // N.B. Phase 0 initialization is executed on all processors. + // + // Verify that the processor block major version number conform + // to the system that is being loaded. + // + + if (Prcb->MajorVersion != PRCB_MAJOR_VERSION) { + KeBugCheck(MISMATCHED_HAL); + } + + // + // Processor 0 specific + // + + if(Prcb->Number == 0) { + + *(PULONG)(& (((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->ActiveProcessor[0]) )=0; + + // + // Set the number of process id's and TB entries. + // + + **((PULONG *)(&KeNumberProcessIds)) = 256; + **((PULONG *)(&KeNumberTbEntries)) = 48; + + // + // Set the interval clock increment value. + // + + HalpCurrentTimeIncrement = MAXIMUM_INCREMENT; + HalpNextTimeIncrement = MAXIMUM_INCREMENT; + HalpNewTimeIncrement = 0; + KeSetTimeIncrement(MAXIMUM_INCREMENT, MINIMUM_INCREMENT); + + + // + // Initialize all spin locks. + // + + KeInitializeSpinLock(&HalpBeepLock); + KeInitializeSpinLock(&HalpDisplayAdapterLock); + KeInitializeSpinLock(&HalpSystemInterruptLock); + KeInitializeSpinLock(&HalpInterruptLock); + KeInitializeSpinLock(&HalpMemoryBufferLock); + + // + // Set address of cache error routine. + // + + KeSetCacheErrorRoutine(HalpCacheErrorRoutine); + + // + // try to identify the Kind of Mainboard => already done in HalpProcessorIdentify + // + +// HalpMainBoard = (MotherBoardType) READ_REGISTER_UCHAR(0xbff0002a); + + if (HalpRevIdESC() == REV_ID_82374_SB ) HalpESC_SB = TRUE; + else HalpESC_SB = FALSE; + + if (HalpMainBoard == M8150) HalpIsTowerPci = TRUE; + + if (HalpIsTowerPci) + HalpLedAddress = (PUCHAR)PCI_TOWER_LED_ADDR; + else + HalpLedAddress = (PUCHAR)PCI_LED_ADDR; + + HalpLedRegister = 0; + + // + // for Isa/Eisa access during phase 0 we use KSEG1 addresses + // + + HalpOnboardControlBase = (PVOID) (EISA_CONTROL_PHYSICAL_BASE | KSEG1_BASE); + + HalpEisaControlBase = (PVOID) (EISA_CONTROL_PHYSICAL_BASE | KSEG1_BASE); + + HalpParseLoaderBlock(LoaderBlock) ; + + HalpInitializePCIBus(); + + // + // Initialize the display adapter. + // + + HalpInitializeDisplay0(LoaderBlock); + +#if DBG + if (!HalPCIRegistryInitialized) HalDisplayString("Non PCI Machine detected\n");; +#endif + + if (!HalPCIRegistryInitialized) HalDisplayString("Non PCI Machine detected - This HAL is not the right one\n");; + + (ULONG)(((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EipRoutine) = (ULONG)-1; + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EipContext = 0; + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EipHalInfo = 0; + + // + // Determine if there is physical memory above 16 MB. + // + + LessThan16Mb = TRUE; + + NextMd = LoaderBlock->MemoryDescriptorListHead.Flink; + + while (NextMd != &LoaderBlock->MemoryDescriptorListHead) { + + Descriptor = CONTAINING_RECORD( NextMd, + MEMORY_ALLOCATION_DESCRIPTOR, + ListEntry ); + + if (Descriptor->BasePage + Descriptor->PageCount > 0x1000) { + LessThan16Mb = FALSE; + } + + NextMd = Descriptor->ListEntry.Flink; + } + + // + // Determine the size need for map buffers. If this system has + // memory with a physical address of greater than + // MAXIMUM_PHYSICAL_ADDRESS, then allocate a large chunk; otherwise, + // allocate a small chunk. + // + + if (LessThan16Mb) { + + // + // Allocate a small set of map buffers. They are only needed for + // slave DMA devices. + // + + HalpMapBufferSize = INITIAL_MAP_BUFFER_SMALL_SIZE; + + } else { + + // + // Allocate a larger set of map buffers. These are used for + // slave DMA controllers and Isa cards. + // + + HalpMapBufferSize = INITIAL_MAP_BUFFER_LARGE_SIZE; + + } + + // + // Allocate map buffers for the adapter objects + // + + HalpMapBufferPhysicalAddress.LowPart = + HalpAllocPhysicalMemory (LoaderBlock, MAXIMUM_PHYSICAL_ADDRESS, + HalpMapBufferSize >> PAGE_SHIFT, TRUE); + HalpMapBufferPhysicalAddress.HighPart = 0; + + if (!HalpMapBufferPhysicalAddress.LowPart) { + + // + // There was not a satisfactory block. Clear the allocation. + // + + HalpMapBufferSize = 0; + } + + // + // Is this machine a multi-processor one ? + // + // If the address of the first restart parameter block is NULL, then + // the host system is a uniprocessor system running with old firmware. + // Otherwise, the host system may be a multiprocessor system if more + // than one restart block is present. + + + NextRestartBlock = SYSTEM_BLOCK->RestartBlock; + if ((NextRestartBlock != NULL) && (NextRestartBlock->NextRestartBlock != NULL)) { + +#if DBG + HalDisplayString("Multiprocessor machine detected by RestartBlock\n"); +#endif + + // + // There is more than one processor + // be sure, the boot (this one) is set to running and started + // + + if (!HalpIsMulti) HalpIsMulti = TRUE; + + NextRestartBlock->BootStatus.ProcessorStart = 1; + NextRestartBlock->BootStatus.ProcessorReady = 1; + + } else { +#if DBG + HalDisplayString("UniProcessor machine detected\n"); +#endif + HalpIsMulti = FALSE; + } + + // Initialize the MP Agent + + if (HalpProcessorId == MPAGENT) { + HalpInitMPAgent(0); + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->ActiveProcessor[PCR->Number] = 0x01; + PCR->InterruptRoutine[OUR_IPI_LEVEL] = HalpIpiInterrupt; + } + + // + // For the moment, we say all Eisa/ Isa(Onboard) Interrupts should go to processor 0 + // + + HalpCreateEisaStructures(Isa); // Initialize Onboard Interrupts and Controller + + // + // Initialize SNI specific interrupts + // (only once needed) + // + + HalpCreateIntPciStructures(); + + // + // Initialize and register a bug check callback record. + // + + KeInitializeCallbackRecord(&HalpCallbackRecord); + KeRegisterBugCheckCallback(&HalpCallbackRecord, + HalpBugCheckCallback, + &HalpBugCheckBuffer, + sizeof(HALP_BUGCHECK_BUFFER), + &HalpComponentId[0]); + + } else { + +#if DBG +// sprintf(HalpBuffer,"HalInitSystem: running on %d\n", HalpGetMyAgent()); +// HalDisplayString(HalpBuffer); +#endif + // + // Place something special only to Slave Processors here ... + // + + HalpInitMPAgent(Prcb->Number); // enables IPI, init cache replace address + PCR->InterruptRoutine[OUR_IPI_LEVEL] = HalpIpiInterrupt; + + + } + + // + // PCR tables and System Timer Initialisation + // + + HalpInitializeInterrupts(); + + if (HalpIsTowerPci){ + + // enable PCI interrupt + + PciData = PCI_TOWER_INTERRUPT_OFFSET | 0x80000000; + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciData)); + + PciData = EN_TARG_INTR | EN_INIT_INT ; + WRITE_REGISTER_ULONG ((PULONG) HalpPciConfigData, *((PULONG) &PciData)); + + // enable PCI parity interrupt + + PciData = PCI_TOWER_COMMAND_OFFSET | 0x80000000; + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciData)); + + PciData = EN_SERR ; + WRITE_REGISTER_ULONG ((PULONG) HalpPciConfigData,READ_REGISTER_ULONG((PULONG) HalpPciConfigData) | *((PULONG) &PciData)); + + + PciData = PCI_TOWER_PAR_0_OFFSET | 0x80000000; + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciData)); + + PciData = 0x1f0 ; + WRITE_REGISTER_ULONG ((PULONG) HalpPciConfigData, *((PULONG) &PciData)); + + // LOCKSPACE for workaround ethernet + PciData = PCI_TOWER_PM_LOCKSPACE | 0x80000000; + WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciData)); + + PciData = 0x80000000 ; + WRITE_REGISTER_ULONG ((PULONG) HalpPciConfigData, *((PULONG) &PciData)); + } + + return (TRUE); + + } else { + + extern BOOLEAN HalpX86BiosInitialized; + + // + // Phase 1 initialization. + // + // N.B. Phase 1 initialization is only executed on processor 0. + + // + // Complete initialization of the display adapter. + // + + if (HalpInitializeDisplay1(LoaderBlock) == FALSE) { + return FALSE; + } + + // + // Mapping of the EISA Control Space via MmMapIoSpace() + // + + HalpMapIoSpace(); + + HalpCalibrateStall(); + + // + // Initialisation of the x86 Bios Emulator ... + // + + x86BiosInitializeBios(HalpEisaControlBase, HalpEisaMemoryBase); + HalpX86BiosInitialized = TRUE; + + // + // Be sure, that the NET_LEVEL is not in the reserved vector . + // (NET_DEFAULT_VECTOR == IPI_LEVEL = 7) => only used for + // machine != RM200 (mainboard 8036) and processor without + // secondary cache + // + + PCR->ReservedVectors &= ~(1 << NET_DEFAULT_VECTOR); + + HalpDisplayCopyRight(); + + return TRUE; + } +} + + +VOID +HalInitializeProcessor ( + IN ULONG Number + ) + +/*++ + +Routine Description: + + This function is called early in the initialization of the kernel + to perform platform dependent initialization for each processor + before the HAL Is fully functional. + + N.B. When this routine is called, the PCR is present but is not + fully initialized. + +Arguments: + + Number - Supplies the number of the processor to initialize. + +Return Value: + + None. + +--*/ + +{ + +// +// The boot processor is already initialized +// + +#if DBG +// sprintf(HalpBuffer,"HalInitializeProcessor %d\n",Number); +// HalDisplayString(HalpBuffer); +#endif + +return; + +} + +BOOLEAN +HalStartNextProcessor ( + IN PLOADER_PARAMETER_BLOCK LoaderBlock, + IN PKPROCESSOR_STATE ProcessorState + ) + +/*++ + +Routine Description: + + This function is called to start the next processor. + +Arguments: + + LoaderBlock - Supplies a pointer to the loader parameter block. + + ProcessorState - Supplies a pointer to the processor state to be + used to start the processor. + +Return Value: + + If a processor is successfully started, then a value of TRUE is + returned. Otherwise a value of FALSE is returned. If a value of + TRUE is returned, then the logical processor number is stored + in the processor control block specified by the loader block. + +--*/ + +{ + + PRESTART_BLOCK NextRestartBlock; + ULONG Number; + PKPRCB Prcb; + + if(!HalpIsMulti) { + return FALSE; + } + + +#if DBG +// sprintf(HalpBuffer,"HalStartNextProcessor running on %d\n", HalpGetMyAgent()); +// HalDisplayString(HalpBuffer); +#endif + + // + // If the address of the first restart parameter block is NULL, then + // the host system is a uniprocessor system running with old firmware. + // Otherwise, the host system may be a multiprocessor system if more + // than one restart block is present. + // + // N.B. The first restart parameter block must be for the boot master + // and must represent logical processor 0. + // + + + NextRestartBlock = SYSTEM_BLOCK->RestartBlock; + if (NextRestartBlock == NULL) { + return FALSE; + } + + // + // Scan the restart parameter blocks for a processor that is ready, + // but not running. If a processor is found, then fill in the restart + // processor state, set the logical processor number, and set start + // in the boot status. + // + + Number = 0; + do { + if ((NextRestartBlock->BootStatus.ProcessorReady != FALSE) && + (NextRestartBlock->BootStatus.ProcessorStart == FALSE)) { + + RtlZeroMemory(&NextRestartBlock->u.Mips, sizeof(MIPS_RESTART_STATE)); + NextRestartBlock->u.Mips.IntA0 = ProcessorState->ContextFrame.IntA0; + NextRestartBlock->u.Mips.Fir = ProcessorState->ContextFrame.Fir; + Prcb = (PKPRCB)(LoaderBlock->Prcb); + Prcb->Number = (CCHAR)Number; + Prcb->RestartBlock = NextRestartBlock; + NextRestartBlock->BootStatus.ProcessorStart = 1; +// +// start it by sending him a special IPI message (SNI special to avoid traffic on +// the MP bus during boot) +// + ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->ActiveProcessor[Number] = 0x01; + HalpSendIpi(1 << (NextRestartBlock->ProcessorId), MPA_BOOT_MESSAGE ); + + HalpIsMulti++; //the number of processors is incremented + + return TRUE; + } + + Number += 1; + NextRestartBlock = NextRestartBlock->NextRestartBlock; + } while (NextRestartBlock != NULL); + + return FALSE; +} + +VOID +HalpVerifyPrcbVersion( + VOID + ) + +/*++ + +Routine Description: + + This function ? + +Arguments: + + None. + + +Return Value: + + None. + +--*/ + +{ + + return; +} + +VOID +HalpDisplayCopyRight( + VOID + ) +/*++ + +Routine Description: + + This function displays the CopyRight Information in the correct SNI Style + +Arguments: + + None. + + +Return Value: + + None. + +--*/ +{ + +// +// Define Identification Strings. +// + HalDisplayString("ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»\n"); +#if defined(SNI_INTERNAL) + HalDisplayString("ºMicrosoft(R) Windows NT(TM) 3.51 Hardware Abstraction Layer º\n"); + HalDisplayString("ºfor Siemens Nixdorf RM200/RM300/RM400 Release 3.0 A0008 º\n"); +#else + HalDisplayString("ºMicrosoft(R) Windows NT(TM) 4.00 Hardware Abstraction Layer º\n"); + HalDisplayString("ºfor Siemens Nixdorf RM200/RM300/RM400 Release 3.0 B0008 º\n"); +#endif + HalDisplayString("ºCopyright(c) Siemens Nixdorf Informationssysteme AG 1996 º\n"); + HalDisplayString("ºCopyright(c) Microsoft Corporation 1985-1996 º\n"); + HalDisplayString("ºAll Rights Reserved º\n"); + HalDisplayString("ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ\n"); + + // + // this does not seem to work correct on NT 3.51 builds (872) at least + // on our MultiPro machine + // + if(!HalpCountCompareInterrupt) { + + HalDisplayString("ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»\n"); + HalDisplayString("ºWARNING: CountCompare Interrupt is not enabled º\n"); + HalDisplayString("ºWARNING: please contact your local Siemens Nixdorf º\n"); + HalDisplayString("ºWARNING: Service Center. º\n"); + HalDisplayString("ºWARNING: º\n"); + HalDisplayString("ºWARNING: Your System will come up - but some º\n"); + HalDisplayString("ºWARNING: performance measurement issues º\n"); + HalDisplayString("ºWARNING: WILL NOT FUNCTION PROPERLY º\n"); + HalDisplayString("ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ\n"); + + } + +} + diff --git a/private/ntos/nthals/halsnip/mips/xxinitnt.c b/private/ntos/nthals/halsnip/mips/xxinitnt.c new file mode 100644 index 000000000..eeb252c3a --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/xxinitnt.c @@ -0,0 +1,345 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/xxinitnt.c,v 1.5 1996/03/04 13:29:07 pierre Exp $") +/*++ + +Copyright (c) 1993 - 1994 Siemens Nixdorf Informationssysteme AG +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + xxinitnt.c + +Abstract: + + + This module implements the interrupt initialization for a MIPS R3000 + or R4000 system. + +Environment: + + Kernel mode only. + + +--*/ + +#include "halp.h" +#include "eisa.h" +extern BOOLEAN HalpCountCompareInterrupt; + +// +// Define forward referenced prototypes. +// + +VOID +HalpAckExtraClockInterrupt( + VOID + ); + +VOID +HalpCountInterrupt ( + VOID + ); + +VOID +HalpProgramIntervalTimer ( + IN ULONG Interval + ); + +VOID +HalpProgramExtraTimer ( + IN ULONG Interval + ); + + +VOID +HalpProgramExtraTimerPciT ( + IN ULONG Interval + ); + + +// +// Put all code for HAL initialization in the INIT section. It will be +// deallocated by memory management when phase 1 initialization is +// completed. +// + +#if defined(ALLOC_PRAGMA) + +#pragma alloc_text(INIT, HalpInitializeInterrupts) +#pragma alloc_text(INIT, HalpCountInterrupt) + +#endif + + +// +// Define the IRQL mask and level mapping table. +// +// These tables are transfered to the PCR and determine the priority of +// interrupts. +// +// N.B. The two software interrupt levels MUST be the lowest levels. +/*+++ + + + The interrupts bits in the cause Register have the following Hardware Interrupts: + + 7 6 5 4 3 2 1 0 + +-------------------------------+ + | x | x | x | x | x | x | x | x | + +-------------------------------+ + | | | | | | | | + | | | | | | | +-------- APC LEVEL (Software) + | | | | | | +------------ Dispatch LEVEL (Software) + | | | | | +---------------- central Int0 (proc 0) + | | | | +-------------------- None + | | | +------------------------ None + | | +---------------------------- TIMER (Proc 1 for RM300MP only) + | +-------------------------------- DCU (Proc 1 for RM400MP only - proc 0 for RM400UP only) + +------------------------------------ CountCompare (Profiling) + +---*/ + +// +// On an PCI Desktop or minitower single-processor (ORION), the processor has only 1 central +// interrupt pin, so all should be directed to this interrupt, except the (internal) +// CountCompare interrupt +// + +UCHAR +HalpIrqlMask_PCIs[] = {3, 3, 3, 3, 3, 3, 3, 3, // 0000 - 0111 high 4-bits + 8, 8, 8, 8, 8, 8, 8, 8, // 1000 - 1111 high 4-bits (CountCompare only!) + 0, 1, 2, 2, 3, 3, 3, 3, // 0000 - 0111 low 4-bits + 3, 3, 3, 3, 3, 3, 3, 3}; // 1000 - 1111 low 4-bits + +UCHAR +HalpIrqlTable_PCIs[] = {0x87, // IRQL 0 + 0x86, // IRQL 1 + 0x84, // IRQL 2 + 0x80, // Int0Dispatch Level + // allow only Irql 8 (profiling & HIGH_LEVEL) ?! + 0x80, // IRQL 4 + 0x80, // IRQL 5 + 0x80, // IRQL 6 + 0x80, // IRQL 7 + 0x00}; // IRQL 8 + + +// +// On a PCI Tower, all the external interrupts are centralised +// on one central pin except DCU on IP6 (because of the extra-timer). +// The internal MP-Agent interrupt is directed on the seventh pin. +// + +UCHAR +HalpIrqlMask_PCIm_ExT[] = {3, 3, 6, 6, 7, 7, 7, 7, // 0000 - 0111 high 4-bits + 8, 8, 8, 8, 8, 8, 8, 8, // 1000 - 1111 high 4-bits (CountCompare only!) + 0, 1, 2, 2, 3, 3, 3, 3, // 0000 - 0111 low 4-bits + 3, 3, 3, 3, 3, 3, 3, 3}; // 1000 - 1111 low 4-bits +UCHAR +HalpIrqlTable_PCIm_ExT[] = {0xe7, // IRQL 0 + 0xe6, // IRQL 1 + 0xe4, // IRQL 2 + 0xe0, // Int0Dispatch Level + 0xe0, // IRQL 4 + 0xe0, // IRQL 5 + 0xc0, // IRQL 6 + 0x80, // IRQL 7 + 0x00}; // IRQL 8 + + +// +// On a PCI multi-processor minitower (or mono-processor with MPagent), +// all the external interrupts are centralised +// on one central pin except extra-timer on IP6 (not used if mono). +// The internal MP-Agent interrupt is directed on the seventh pin. +// + +UCHAR +HalpIrqlMask_PCIm[] = {3, 5, 3, 5, 7, 7, 7, 7, // 0000 - 0111 high 4-bits + 8, 8, 8, 8, 8, 8, 8, 8, // 1000 - 1111 high 4-bits (CountCompare only!) + 0, 1, 2, 2, 3, 3, 3, 3, // 0000 - 0111 low 4-bits + 3, 3, 3, 3, 3, 3, 3, 3}; // 1000 - 1111 low 4-bits +UCHAR +HalpIrqlTable_PCIm[] = {0xd7, // IRQL 0 + 0xd6, // IRQL 1 + 0xd4, // IRQL 2 + 0xd0, // Int0Dispatch Level + 0xd0, // IRQL 4 + 0xc0, // IRQL 5 + 0xc0, // IRQL 6 + 0x80, // IRQL 7 + 0x00}; // IRQL 8 + + + +VOID +HalpCountInterrupt ( + VOID + ) + +/*++ + +Routine Description: + + This function serves as the R4000 count/compare interrupt service + routine early in the system initialization. Its only function is + to field and acknowledge count/compare interrupts during the system + boot process. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + + extern ULONG HalpProfileInterval; + + // + // Acknowledge the R4000 count/compare interrupt. + // + HalpProfileInterval = DEFAULT_PROFILE_INTERVAL; + HalpCountCompareInterrupt = TRUE; + + HalpWriteCompareRegisterAndClear(DEFAULT_PROFILE_COUNT); + return; +} + +BOOLEAN +HalpInitializeInterrupts ( + VOID + ) + +/*++ + +Routine Description: + + This function initializes interrupts for a MIPS R3000 or R4000 system. + +Arguments: + + None. + +Return Value: + + A value of TRUE is returned if the initialization is successfully + completed. Otherwise a value of FALSE is returned. + +--*/ + +{ + ULONG Index; + PKPRCB Prcb; + + + // + // Get the address of the processor control block for the current + // processor. + // + + Prcb = PCR->Prcb; + + if (Prcb->Number == 0) { + + // + // Initialize the IRQL translation tables in the PCR. These tables are + // used by the interrupt dispatcher to determine the new IRQL and the + // mask value that is to be loaded into the PSR. They are also used by + // the routines that raise and lower IRQL to load a new mask value into + // the PSR. + // + + if (HalpProcessorId != MPAGENT) { + + // + // this is a PCI desktop or a single-processor PCI minitower + // + + for (Index = 0; Index < sizeof(HalpIrqlMask_PCIs); Index += 1) + PCR->IrqlMask[Index] = HalpIrqlMask_PCIs[Index]; + for (Index = 0; Index < sizeof(HalpIrqlTable_PCIs); Index += 1) + PCR->IrqlTable[Index] = HalpIrqlTable_PCIs[Index]; + + } else { + + // + // this is a PCI minitower or PCI tower + // + + if (HalpIsTowerPci){ + for (Index = 0; Index < sizeof(HalpIrqlMask_PCIm_ExT); Index += 1) + PCR->IrqlMask[Index] = HalpIrqlMask_PCIm_ExT[Index]; + for (Index = 0; Index < sizeof(HalpIrqlTable_PCIm_ExT); Index += 1) + PCR->IrqlTable[Index] = HalpIrqlTable_PCIm_ExT[Index]; + }else{ + for (Index = 0; Index < sizeof(HalpIrqlMask_PCIm); Index += 1) + PCR->IrqlMask[Index] = HalpIrqlMask_PCIm[Index]; + for (Index = 0; Index < sizeof(HalpIrqlTable_PCIm); Index += 1) + PCR->IrqlTable[Index] = HalpIrqlTable_PCIm[Index]; + } + + } + + // + // the main system clock is always in the onboard PC core + // + + PCR->InterruptRoutine[CLOCK2_LEVEL] = (PKINTERRUPT_ROUTINE)HalpStallInterrupt; + + // + // force a CountCompare interrupt + // + + HalpWriteCompareRegisterAndClear(100); + + // + // If processor 0 is being initialized, then connect the count/compare + // interrupt to the count interrupt routine to handle early count/compare + // interrupts during phase 1 initialization. Otherwise, connect the + // count\compare interrupt to the appropriate interrupt service routine. + // + + PCR->InterruptRoutine[PROFILE_LEVEL] = HalpCountInterrupt; + + HalpProgramIntervalTimer (MAXIMUM_INCREMENT); + HalpEnableOnboardInterrupt(CLOCK2_LEVEL,Latched); // Enable Timer1,Counter0 interrupt + + } else { + + // + // MultiProcessorEnvironment Processor N + // + + if (HalpIsTowerPci){ + for (Index = 0; Index < sizeof(HalpIrqlMask_PCIm_ExT); Index += 1) + PCR->IrqlMask[Index] = HalpIrqlMask_PCIm_ExT[Index]; + for (Index = 0; Index < sizeof(HalpIrqlTable_PCIm_ExT); Index += 1) + PCR->IrqlTable[Index] = HalpIrqlTable_PCIm_ExT[Index]; + }else{ + for (Index = 0; Index < sizeof(HalpIrqlMask_PCIm); Index += 1) + PCR->IrqlMask[Index] = HalpIrqlMask_PCIm[Index]; + for (Index = 0; Index < sizeof(HalpIrqlTable_PCIm); Index += 1) + PCR->IrqlTable[Index] = HalpIrqlTable_PCIm[Index]; + } + + if (Prcb->Number==1){ + if (HalpIsTowerPci){ + HalpProgramExtraTimerPciT(MAXIMUM_INCREMENT); + }else{ + HalpProgramExtraTimer (MAXIMUM_INCREMENT); + PCR->InterruptRoutine[EXTRA_CLOCK_LEVEL] = HalpClockInterrupt1; + } + } + + PCR->InterruptRoutine[PROFILE_LEVEL] = HalpProfileInterrupt; + PCR->StallScaleFactor = HalpStallScaleFactor; + + } + + return TRUE; +} + diff --git a/private/ntos/nthals/halsnip/mips/xxipiint.s b/private/ntos/nthals/halsnip/mips/xxipiint.s new file mode 100644 index 000000000..20c0302ac --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/xxipiint.s @@ -0,0 +1,56 @@ +// TITLE("Interprocessor Interrupts") +//++ +// +// Copyright (c) 1993-1994 Microsoft Corporation +// +// Module Name: +// +// xxipiint.s +// +// Abstract: +// +// This module implements the code necessary to field and process the +// interprocessor interrupts on a MIPS R4000 Duo system. +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// +//-- + +#include "halmips.h" + + + + SBTTL("Interprocessor Interrupt") +//++ +// +// Routine Description: +// +// This routine is entered as the result of an interprocessor interrupt. +// Its function is to acknowledge the interrupt and transfer control to +// the standard system routine to process interprocessor requrests. +// +// Arguments: +// +// s8 - Supplies a pointer to a trap frame. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpIpiInterrupt) + +// +// Inter processor interrupt processing +// + + move a0,s8 + j HalpProcessIpi // acknowledgement Ipi + + .end HalpIpiInterrupt + diff --git a/private/ntos/nthals/halsnip/mips/xxmemory.c b/private/ntos/nthals/halsnip/mips/xxmemory.c new file mode 100644 index 000000000..2d9806212 --- /dev/null +++ b/private/ntos/nthals/halsnip/mips/xxmemory.c @@ -0,0 +1,246 @@ +//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/xxmemory.c,v 1.2 1996/02/23 17:55:12 pierre Exp $") + +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + xxmemory.c + +Abstract: + + Provides routines to allow the HAL to map physical memory. + +Environment: + + Phase 0 initialization only. + +Changes: + + All stuff comes from the x86 HAL Sources (xxmemory.c) + +--*/ +#include "halp.h" + +// +// Put all code for HAL initialization in the INIT section. It will be +// deallocated by memory management when phase 1 initialization is +// completed. +// + +#if defined(ALLOC_PRAGMA) +#pragma alloc_text(INIT, HalpAllocPhysicalMemory) +#endif + + +MEMORY_ALLOCATION_DESCRIPTOR HalpExtraAllocationDescriptor; + +ULONG +HalpAllocPhysicalMemory( + IN PLOADER_PARAMETER_BLOCK LoaderBlock, + IN ULONG MaxPhysicalAddress, + IN ULONG NoPages, + IN BOOLEAN bAlignOn64k + ) +/*++ + +Routine Description: + + Carves out N pages of physical memory from the memory descriptor + list in the desired location. This function is to be called only + during phase zero initialization. (ie, before the kernel's memory + management system is running) + +Arguments: + + MaxPhysicalAddress - The max address where the physical memory can be + NoPages - Number of pages to allocate + +Return Value: + + The pyhsical address or NULL if the memory could not be obtained. + +--*/ +{ + PMEMORY_ALLOCATION_DESCRIPTOR Descriptor; + PLIST_ENTRY NextMd; + ULONG AlignmentOffset; + ULONG MaxPageAddress; + ULONG PhysicalAddress; + + + MaxPageAddress = MaxPhysicalAddress >> PAGE_SHIFT; + + + // + // Scan the memory allocation descriptors and allocate map buffers + // + + NextMd = LoaderBlock->MemoryDescriptorListHead.Flink; + while (NextMd != &LoaderBlock->MemoryDescriptorListHead) { + Descriptor = CONTAINING_RECORD(NextMd, + MEMORY_ALLOCATION_DESCRIPTOR, + ListEntry); + + AlignmentOffset = bAlignOn64k ? + ((Descriptor->BasePage + 0x0f) & ~0x0f) - Descriptor->BasePage : + 0; + + // + // Search for a block of memory which contains a memory chunk + // that is greater than size pages, and has a physical address less + // than MAXIMUM_PHYSICAL_ADDRESS. + // + + if ((Descriptor->MemoryType == LoaderFree || + Descriptor->MemoryType == MemoryFirmwareTemporary) && + (Descriptor->BasePage) && + (Descriptor->PageCount >= NoPages + AlignmentOffset) && + (Descriptor->BasePage + NoPages + AlignmentOffset < MaxPageAddress)) { + + PhysicalAddress = (AlignmentOffset + Descriptor->BasePage) + << PAGE_SHIFT; + + break; + } + + NextMd = NextMd->Flink; + } + + // + // Use the extra descriptor to define the memory at the end of the + // original block. + // + + + ASSERT(NextMd != &LoaderBlock->MemoryDescriptorListHead); + + if (NextMd == &LoaderBlock->MemoryDescriptorListHead) + + return (ULONG)NULL; + + // + // Adjust the memory descriptors. + // + + if (AlignmentOffset == 0) { + + Descriptor->BasePage += NoPages; + Descriptor->PageCount -= NoPages; + + if (Descriptor->PageCount == 0) { + + // + // The whole block was allocated, + // Remove the entry from the list completely. + // + + RemoveEntryList(&Descriptor->ListEntry); + + } + + } else { + + if (Descriptor->PageCount - NoPages - AlignmentOffset) { + + // + // Currently we only allow one Align64K allocation + // + ASSERT (HalpExtraAllocationDescriptor.PageCount == 0); + + // + // The extra descriptor is needed so intialize it and insert + // it in the list. + // + HalpExtraAllocationDescriptor.PageCount = + Descriptor->PageCount - NoPages - AlignmentOffset; + + HalpExtraAllocationDescriptor.BasePage = + Descriptor->BasePage + NoPages + AlignmentOffset; + + HalpExtraAllocationDescriptor.MemoryType = MemoryFree; + InsertTailList( + &Descriptor->ListEntry, + &HalpExtraAllocationDescriptor.ListEntry + ); + } + + + // + // Use the current entry as the descriptor for the first block. + // + + Descriptor->PageCount = AlignmentOffset; + } + + + return PhysicalAddress; +} + + +#define MEMBASE 0x20000000 + +USHORT HalpComputeNum (phys_addr) +UCHAR *phys_addr; +{ + USHORT board_or_simm_num; + ULONG i; + struct bank *pbank =((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->MemConfArea; + ULONG nb_banks =((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))-> NbMemBanks; + UCHAR *conf_addr; + + + + if (pbank == 0) return((USHORT)(-1)); // firmware revision < 4.5 --> function non implemented + + + // Rebase phys_addr at 0x20000000 + (ULONG)phys_addr |= MEMBASE; + + for (i = 0; i < nb_banks; i++, pbank++) { + + // Rebase conf_addr at 0x20000000 + conf_addr =(UCHAR *)( (ULONG)pbank->first_addr | MEMBASE); + + if ((phys_addr >= conf_addr) && (phys_addr < (conf_addr + pbank->first_piece_size))){ + + break; + } + + if (pbank->second_piece_size != 0) { + + // Rebase conf_addr at 0x20000000 + conf_addr =(UCHAR *)((ULONG) pbank->second_addr | MEMBASE); + + if ((phys_addr >= conf_addr) && (phys_addr < (conf_addr + pbank->second_piece_size))) { + + break; + } + } + } + + if (i == nb_banks) { + + // Unable to find the board or SIMM + board_or_simm_num = (USHORT)(-1); + } + + else { + // On RM400 we have one board per bank from 1 to nb_banks + if (HalpIsTowerPci) { + board_or_simm_num = (USHORT)(i + 1); + } + // On RM200/RM300 we have two SIMM's per bank from 0 to 2*nb_banks - 1 + else { + board_or_simm_num = (USHORT)( (2*i) + (((ULONG)phys_addr >> 3) & 0x01)); + } + } + + return (board_or_simm_num); +} + + + + + |