summaryrefslogtreecommitdiffstats
path: root/private/ntos/nthals/halsni4x/mips
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/nthals/halsni4x/mips')
-rw-r--r--private/ntos/nthals/halsni4x/mips/allstart.c59
-rw-r--r--private/ntos/nthals/halsni4x/mips/cacherr.s196
-rw-r--r--private/ntos/nthals/halsni4x/mips/deskdef.h93
-rw-r--r--private/ntos/nthals/halsni4x/mips/duocache.s774
-rw-r--r--private/ntos/nthals/halsni4x/mips/halp.h161
-rw-r--r--private/ntos/nthals/halsni4x/mips/i82c54.h34
-rw-r--r--private/ntos/nthals/halsni4x/mips/j4cache.s1064
-rw-r--r--private/ntos/nthals/halsni4x/mips/j4flshbf.s53
-rw-r--r--private/ntos/nthals/halsni4x/mips/j4flshio.c202
-rw-r--r--private/ntos/nthals/halsni4x/mips/j4prof.c325
-rw-r--r--private/ntos/nthals/halsni4x/mips/jxbeep.c132
-rw-r--r--private/ntos/nthals/halsni4x/mips/jxebsup.c2851
-rw-r--r--private/ntos/nthals/halsni4x/mips/jxenvirv.c192
-rw-r--r--private/ntos/nthals/halsni4x/mips/jxhwsup.c2437
-rw-r--r--private/ntos/nthals/halsni4x/mips/jxmapio.c133
-rw-r--r--private/ntos/nthals/halsni4x/mips/jxport.c805
-rw-r--r--private/ntos/nthals/halsni4x/mips/jxreturn.c239
-rw-r--r--private/ntos/nthals/halsni4x/mips/jxsysint.c380
-rw-r--r--private/ntos/nthals/halsni4x/mips/jxtime.c334
-rw-r--r--private/ntos/nthals/halsni4x/mips/jxusage.c47
-rw-r--r--private/ntos/nthals/halsni4x/mips/minidef.h141
-rw-r--r--private/ntos/nthals/halsni4x/mips/mpagent.c681
-rw-r--r--private/ntos/nthals/halsni4x/mips/mpagent.h535
-rw-r--r--private/ntos/nthals/halsni4x/mips/orcache.s628
-rw-r--r--private/ntos/nthals/halsni4x/mips/r4intdsp.c1052
-rw-r--r--private/ntos/nthals/halsni4x/mips/snidef.h215
-rw-r--r--private/ntos/nthals/halsni4x/mips/snidisp.c1475
-rw-r--r--private/ntos/nthals/halsni4x/mips/snihalp.h338
-rw-r--r--private/ntos/nthals/halsni4x/mips/sniregs.h139
-rw-r--r--private/ntos/nthals/halsni4x/mips/unicache.s1098
-rw-r--r--private/ntos/nthals/halsni4x/mips/vgadata.h406
-rw-r--r--private/ntos/nthals/halsni4x/mips/x4clock.s325
-rw-r--r--private/ntos/nthals/halsni4x/mips/x4misc.s472
-rw-r--r--private/ntos/nthals/halsni4x/mips/x4tb.s110
-rw-r--r--private/ntos/nthals/halsni4x/mips/x86bios.c191
-rw-r--r--private/ntos/nthals/halsni4x/mips/xxcache.c399
-rw-r--r--private/ntos/nthals/halsni4x/mips/xxcalstl.c270
-rw-r--r--private/ntos/nthals/halsni4x/mips/xxclock.c233
-rw-r--r--private/ntos/nthals/halsni4x/mips/xxidle.s78
-rw-r--r--private/ntos/nthals/halsni4x/mips/xxinithl.c746
-rw-r--r--private/ntos/nthals/halsni4x/mips/xxinitnt.c369
-rw-r--r--private/ntos/nthals/halsni4x/mips/xxipiint.s56
-rw-r--r--private/ntos/nthals/halsni4x/mips/xxmemory.c179
43 files changed, 20647 insertions, 0 deletions
diff --git a/private/ntos/nthals/halsni4x/mips/allstart.c b/private/ntos/nthals/halsni4x/mips/allstart.c
new file mode 100644
index 000000000..8e4dbcc41
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/allstart.c
@@ -0,0 +1,59 @@
+/*++
+
+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"
+
+extern VOID HalpInit2MPAgent( );
+
+
+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 ((PCR->Number == HalpNetProcessor) && (HalpProcessorId == MPAGENT)){
+ PCR->InterruptRoutine[NETMULTI_LEVEL] = (PKINTERRUPT_ROUTINE)HalpRM400Int5Process;
+ HalpInit2MPAgent( );
+ }
+
+ return TRUE;
+
+}
diff --git a/private/ntos/nthals/halsni4x/mips/cacherr.s b/private/ntos/nthals/halsni4x/mips/cacherr.s
new file mode 100644
index 000000000..a8363b179
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/cacherr.s
@@ -0,0 +1,196 @@
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk35/src/hal/halsni/mips/RCS/cacherr.s,v 1.1 1994/10/13 15:47:06 holli 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.
+//
+// N.B. All the code in this routine MUST run in KSEG1 and reference
+// data only in KSEG1 until which time as any cache errors have
+// been corrected.
+//
+// N.B. This routine is NOT COMPLETE. All cache errors result in a
+// soft reset.
+//
+// Environment:
+//
+// Kernel mode only.
+//
+// Revision History:
+//
+//--
+
+#include "halmips.h"
+
+//
+// Define local save area for register state.
+//
+
+ .data
+SavedAt:.space 4 // saved integer register at - a3
+SavedV0:.space 4 //
+SavedV1:.space 4 //
+SavedA0:.space 4 //
+SavedA1:.space 4 //
+SavedA2:.space 4 //
+SavedA3:.space 4 //
+
+ SBTTL("Cache Error Handling")
+//++
+//
+// VOID
+// HalpCacheErrorRoutine (
+// VOID
+// )
+//
+// Routine Description:
+//
+// This function is entered from the cache error vector executing
+// in KSEG1. If the error is a single bit ECC error in the second
+// level data cache or the error is in the primary instruction cache,
+// then the error is corrected and execution is continued. Otherwise,
+// a fatal system error has occured and control is transfered to the
+// soft reset vector.
+//
+// N.B. No state has been saved when this routine is entered.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalpCacheErrorRoutine)
+
+//
+// Save volatile registers needed to fix cache error.
+//
+
+ .set noreorder
+ .set noat
+ la k0,SavedAt // get address of register save area
+ li k1,KSEG1_BASE // convert address of KSEG1 address
+ or k0,k0,k1 //
+ sw AT,0(k0) // save registers AT - a3
+ sw v0,4(k0) //
+ sw v1,8(k0) //
+ sw a0,12(k0) //
+ sw a1,16(k0) //
+ sw a2,20(k0) //
+
+//
+// Get the current processor state and cache error register, and check
+// if the error can be corrected.
+//
+
+ mfc0 v0,psr // get current processor state
+ mfc0 v1,cacheerr // get cache error state
+ .set at
+ .set reorder
+
+//
+// ****** temp ******
+//
+// The following code is temporary and will be removed when full cache
+// error support is included.
+//
+// ****** temp ******
+//
+
+ b SoftReset // ****** all error soft rest
+
+//
+// If the EXL bit is set in the processor state, then the error is not
+// recoverable because the EXL bit may be erroneously set (errata) and
+// it cannot be determined whether is should or should not be set, e.g.,
+// the exact addresses ranges over which EXL might be correctly set are
+// not verifiable. Also, k0 and k1 are destroyed before they are saved
+// and are used by the exception handling code (there is no way to save
+// a register in noncached memory wihtout the use of a register).
+//
+
+ sll a0,v0,31 - PSR_EXL // shift EXL bit in sign
+ bltz a0,SoftReset // if ltz, error not correctable
+
+//
+// If the error occured on the SysAd bus, then the error is not correctable.
+//
+
+ sll a0,v1,31 - CACHEERR_EE // shift EE bit into sign
+ bltz a0,SoftReset // if ltz, error not correctable
+
+//
+// Determine whether the error is in the instruction or data cache.
+//
+
+ sll a0,v1,31 - CACHEERR_ER // shift ER bit into sign
+ bgez a0,IcacheError // if gez, instruction cache error
+
+//
+// The error occured in the data cache.
+//
+// If the error is a data error in the primary cache, then the error
+// is not correctable since the cache line dirty bit is included in
+// the parity calculation and therefore may be wrong.
+//
+
+DcacheError: //
+ sll a0,v1,31 - CACHEERR_EC // shift EC bit into sign
+ bgez a0,SoftReset // if gez, error in primary cache
+ b ExitError // exit error
+
+//
+// The error occured in the instruction cache.
+//
+// If the error occured in the secondary data cache, then the error is not
+// correctable since there is not secondary instruciton cache.
+//
+
+IcacheError: //
+ sll a0,v1,31 - CACHEERR_EC // shift EC bit into sign
+ bltz a0,SoftReset // if ltz, error in secondary cache
+
+//
+// The cache error has been corrected - restore register state and continue
+// execution.
+//
+
+ExitError: //
+
+ .set noreorder
+ .set noat
+ la k0,SavedAt // get address of register save area
+ li k1,KSEG1_BASE // convert address of KSEG1 address
+ or k0,k0,k1 //
+ lw AT,0(k0) // restore registers AT - a3
+ lw v0,4(k0) //
+ lw v1,8(k0) //
+ lw a0,12(k0) //
+ lw a1,16(k0) //
+ lw a2,20(k0) //
+ eret //
+ .set at
+ .set reorder
+
+//
+// Cache error cannot be corrected - transfer control to soft reset vector.
+//
+
+SoftReset: //
+ la k0,SOFT_RESET_VECTOR // get address of soft reset vector
+ j k0 // perform a soft reset
+
+ .end HalpCacheErrorRoutine
diff --git a/private/ntos/nthals/halsni4x/mips/deskdef.h b/private/ntos/nthals/halsni4x/mips/deskdef.h
new file mode 100644
index 000000000..54ec5c26c
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/deskdef.h
@@ -0,0 +1,93 @@
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk35/src/hal/halsni/mips/RCS/deskdef.h,v 1.1 1994/10/13 15:47:06 holli Exp $")
+/*+++
+
+Copyright (c) 1993-1994 Siemens Nixdorf Informationssysteme AG
+
+Module Name:
+
+ DESKdef.h
+
+Abstract:
+
+ This file describes hardware addresses for the new
+ SNI Desktop Model (RM200)
+ which are not common to all SNI machines.
+
+
+
+---*/
+
+#ifndef _DESKDEF_
+#define _DESKDEF_
+
+//
+// define various masks for the interrupt sources register
+//
+/*
+ The interrupt Source Register on an Desktop has the following bits:
+
+ 7 6 5 4 3 2 1 0
+ +---------------|---------------+
+ | 0 | 0 | x | 0 | 1 | 0 | 1 | 1 | 0 Low Activ; 1 High activ; x not connected
+ +---------------|---------------+
+ |________ ISA (onboard)Interrupt
+ |____________ EISA (extension board) Interrupt
+ |________________ SCSI Interrupt (SCSI Driver)
+ |____________________ Ethernet (Net driver)
+ |________________________ Push Button (HalpInt5Dispatch)
+ |____________________________ unused
+ |________________________________ TimeOut Interrupt
+ |____________________________________ Eisa extension board installed
+
+*/
+
+#define RM200_ONBOARD_MASK 0x01
+#define RM200_EISA_MASK 0x02
+#define RM200_SCSI_MASK 0x04
+#define RM200_NET_MASK 0x08
+#define RM200_PB_MASK 0x10
+#define RM200_TIMEOUT_MASK 0x20
+#define RM200_INTERRUPT_MASK 0x54
+
+#define RM200_ONBOARD_CONTROL_PHYSICAL_BASE 0x16000000
+#define RM200_ONBOARD_MEMORY_PHYSICAL_BASE 0x12000000
+#define RM200_ONBOARD_IO (RM200_ONBOARD_CONTROL_PHYSICAL_BASE | KSEG1_BASE)
+#define RM200_ONBOARD_MEMORY (RM200_ONBOARD_MEMORY_PHYSICAL_BASE | KSEG1_BASE)
+
+//
+// SNI ASIC registers
+//
+
+
+#define RM200_ONBOARD_INT_ACK_PHYSICAL_BASE 0x1a080000 // physical base of interrupt (ext. request) register
+#define RM200_ONBOARD_INT_ACK_REGISTER 0xba080000 // physical base | KSEG1_BASE
+#define RM200_EISA_INT_ACK_PHYSICAL_BASE 0x1a000000 // physical base of EISA interrupt ack for the chipset
+#define RM200_EISA_INT_ACK_REGISTER 0xba000000 // physical base | KSEG1_BASE
+#define RM200_INTERRUPT_SOURCE_PHYSICAL_BASE 0x1c000000 // physical base of interrupt source register
+#define RM200_INTERRUPT_SOURCE_REGISTER 0xbc000000 // physical base | KSEG1_BASE
+#define RM200_INTERRUPT_MASK_PHYSICAL_BASE 0x1c080000 // physical base of interrupt mask register
+#define RM200_INTERRUPT_MASK_REGISTER 0xbc080000 // physical base | KSEG1_BASE
+
+#define RM200_ONBOARD_MAP_PHYSICAL_BASE 0x1fc80000 // physical base of ISA map register (for BusMaster Devices)
+#define RM200_ONBOARD_MAP 0xbfc80000 // physical base | KSEG1_BASE
+#define RM200_EXTENSION_BOARD_MAP_PHYS_BASE 0x1fca0000 // physical base of ISA map register (for BusMaster Devices)
+#define RM200_EXTENSION_BOARD_MAP 0xbfca0000 // physical base | KSEG1_BASE
+#define RM200_VESA_MAP_PHYSICAL_BASE 0x1fcc0000 // physical base of VLB map register
+#define RM200_VESA_MAP 0xbfcc0000 // physical base | KSEG1_BASE
+#define RM200_ONBOARD_VRAM_PHYSICAL_BASE 0x1e000000 // physical base of onboard Video Ram
+#define RM200_ONBOARD_VRAM 0xbe000000 // physical base | KSEG1_BASE
+
+
+#define RM200_LED_PHYSICAL_ADDR 0x1fe00000 // LED Register physical
+#define RM200_LED_ADDR 0xbfe00000 // LED Register | KSEG1_BASE
+#define RM200_MCR_PHYSICAL_ADDR 0x1fd80000 // MachineConfigRegister
+#define RM200_MCR_ADDR 0xbfd80000 // MachineConfigRegister | KSEG1
+
+#define RM200_NVRAM_PHYSICAL_BASE 0x1cd40000 // physical base of nonvolatile RAM and RTC
+#define RM200_REAL_TIME_CLOCK_ADDRESS 0x1cd40000 // physical base of RTC
+#define RM200_REAL_TIME_CLOCK 0xbcd40000 // physical base of RTC | KSEG1_BASE
+#define RM200_RESET_DBG_BUT 0xbfe80000 // reset debugger int | KSEG1_BASE
+#define RM200_RESET_TEMPBAT_INTR 0xbfe80000 // reset Temperature/Battery int | KSEG1
+
+
+#endif // _DESKDEF_
diff --git a/private/ntos/nthals/halsni4x/mips/duocache.s b/private/ntos/nthals/halsni4x/mips/duocache.s
new file mode 100644
index 000000000..a869cdde7
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/duocache.s
@@ -0,0 +1,774 @@
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halvlbms/src/hal/halsni4x/mips/RCS/duocache.s,v 1.1 1995/05/19 10:44:26 flo 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
+
+
+
+ LEAF_ENTRY(HalpGetTaglo)
+
+ .set noreorder
+ .set noat
+
+ cache INDEX_LOAD_TAG_SD,0(a0) // get a copy of the SLC TAG
+ mfc0 v0, taglo
+// and v0, v0, 0xffff8000 // mask address bits A18:A17
+ sll v0, v0, 4 // dismiss A35:A32
+
+ .set at
+ .set reorder
+
+ j ra // return
+
+ .end HalpGetTaglo
+
+
+//
+// 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("MpAgent Identification")
+//++
+//
+// VOID
+// HalpMpAgentIdentify()
+//
+// Routine Description:
+//
+// This function attempts to access to the MpAgent registers (base = 0x1ffff000).
+// It reads 'base' and 'base + 0x40' addresses which correspond to two different registers
+// of the MP Agent so two different contents.
+// If there is no existing MPAgent, the hardware will access in fact the old Asic
+// (base 0x1fff0000). Only 'base' to 'base+0x32' addresses are existing for this ASIC.
+// So when we will attempt to access to 'base+0x40', we will read 'base'. So we will
+// see that 'base' and 'base+0x40' have the same contents.
+// WARNING : cache error must be disabled to access to the single processor ASIC
+//
+// Arguments:
+//
+// None
+//
+// Return Value:
+//
+// TRUE : a MpAgent is detected
+// FALSE : no MpAgent
+//
+//--
+
+ LEAF_ENTRY(HalpMpAgentIdentify)
+
+ .set noreorder
+ mfc0 a0,psr // get current PSR
+ nop // fill
+ nop
+ nop
+ nop
+ move a3,a0
+ or a0,a0,0x00010000 // disable error cache to access single proc ASIC
+ mtc0 a0,psr
+ nop // fill
+ nop
+ nop
+ nop
+
+ li a0,0xbffff000 // MpAgent address
+ lw a1,0(a0) // address + 0
+ lw a2,0x40(a0) // address + 0x40
+ li v0,0x01
+ beql a2,a1,10f
+ li v0,0x00 // v0 = 0 only if a2 == a1 (branch likely)
+
+10:
+ mtc0 a3,psr // restore PSR
+ nop // fill
+ nop
+ nop
+ nop
+ .set reorder
+
+ j ra
+
+ .end HalpMpAgentIdentify
+
+ 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
+ la t0, HalpLedAddress // get the address for the LED register
+ lw t0, 0(t0)
+ lw t1, KiPcr + PcSetMember(zero) // get a bitmapped value for Processor Number
+ or t1, t1, FLUSH_DCACHE_PAGE // what are we doing ?
+ xor t1, t1, 0xff // inverse
+ sb t1, 0(t0) // display it
+
+#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
+
+ li a3,MPAGENT_RESERVED | KSEG0_BASE // 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
+
+ la t0, HalpLedAddress // get the address for the LED register
+ lw t0, 0(t0)
+ lw t1, KiPcr + PcSetMember(zero) // get a bitmapped value for Processor Number
+ or t1, t1, PURGE_ICACHE_PAGE // what are we doing ?
+ xor t1, t1, 0xff // inverse
+ sb t1, 0(t0) // display it
+#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.
+//
+
+//
+// multi-processor machine
+//
+
+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
+
+ li a2, MPAGENT_RESERVED | KSEG0_BASE
+
+ 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)
+
+ 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
+ la t0, HalpLedAddress // get the address for the LED register
+ lw t0, 0(t0)
+ lw t1, KiPcr + PcSetMember(zero) // get a bitmapped value for Processor Number
+ or t1, t1, SWEEP_DCACHE // what are we doing ?
+ xor t1, t1, 0xff // inverse
+ sb t1, 0(t0) // display it
+#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
+
+ li a0,MPAGENT_RESERVED | KSEG0_BASE // 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
+ la t0, HalpLedAddress // get the address for the LED register
+ lw t0, 0(t0)
+ lw t1, KiPcr + PcSetMember(zero) // get a bitmapped value for Processor Number
+ or t1, t1, SWEEP_ICACHE // what are we doing ?
+ xor t1, t1, 0xff // inverse
+ sb t1, 0(t0) // display it
+#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
+ beq zero,t1,20f // if eq, no second level cache
+ li a0,MPAGENT_RESERVED | KSEG0_BASE // 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
+#if DBG
+ la t0, HalpLedAddress // get the address for the LED register
+ lw t0, 0(t0)
+ lw t1, KiPcr + PcSetMember(zero) // get a bitmapped value for Processor Number
+ or t1, t1, ZERO_PAGE // what are we doing ?
+ xor t1, t1, 0xff // inverse
+ sb t1, 0(t0) // display it
+#endif
+
+ 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
+
+
diff --git a/private/ntos/nthals/halsni4x/mips/halp.h b/private/ntos/nthals/halsni4x/mips/halp.h
new file mode 100644
index 000000000..647f51316
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/halp.h
@@ -0,0 +1,161 @@
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk351/src/hal/halsni4x/mips/RCS/halp.h,v 1.1 1995/05/19 10:44:50 flo 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"
+
+
+//
+// Define function prototypes.
+//
+
+ULONG
+HalpAllocateTbEntry (
+ VOID
+ );
+
+VOID
+HalpFreeTbEntry (
+ VOID
+ );
+
+VOID
+HalpCacheErrorRoutine (
+ VOID
+ );
+
+BOOLEAN
+HalpCalibrateStall (
+ VOID
+ );
+
+VOID
+HalpClockInterrupt(
+ 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
+HalpProcessIpi (
+ IN struct _KTRAP_FRAME *TrapFrame
+ );
+
+VOID
+HalpInitMPAgent (
+ IN ULONG Number
+ );
+
+ULONG
+HalpGetMyAgent(
+ VOID
+ );
+
+BOOLEAN
+HalpCheckSpuriousInt(
+ VOID
+ );
+
+VOID
+HalpBootCpuRestart(
+ VOID
+ );
+
+ULONG
+HalpGetTaglo(
+ IN ULONG Address
+ );
+
+//
+// Define external references.
+//
+
+extern ULONG HalpCurrentTimeIncrement;
+extern ULONG HalpNextTimeIncrement;
+extern ULONG HalpNewTimeIncrement;
+extern KSPIN_LOCK HalpBeepLock;
+extern KSPIN_LOCK HalpDisplayAdapterLock;
+extern KSPIN_LOCK HalpSystemInterruptLock;
+extern KSPIN_LOCK HalpDmaLock;
+extern ULONG HalpProfileCountRate;
+extern ULONG HalpStallScaleFactor;
+extern LONG HalpNetProcessor;
+
+#endif // _HALP_
diff --git a/private/ntos/nthals/halsni4x/mips/i82c54.h b/private/ntos/nthals/halsni4x/mips/i82c54.h
new file mode 100644
index 000000000..17e77af31
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/i82c54.h
@@ -0,0 +1,34 @@
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk35/src/hal/halsni/mips/RCS/i82c54.h,v 1.1 1994/10/13 15:47:06 holli 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/halsni4x/mips/j4cache.s b/private/ntos/nthals/halsni4x/mips/j4cache.s
new file mode 100644
index 000000000..dbf8b8eb5
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/j4cache.s
@@ -0,0 +1,1064 @@
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk35/src/hal/halsni/mips/RCS/j4cache.s,v 1.1 1994/10/13 15:47:06 holli Exp $")
+// TITLE("Cache Flush")
+//++
+//
+// Copyright (c) 1991-1993 Microsoft Corporation
+//
+// Module Name:
+//
+// j4cache.s
+//
+// Abstract:
+//
+// This module implements the code necessary for cache operations on
+// a MIPS R4000.
+//
+// Environment:
+//
+// Kernel mode only.
+//
+//--
+
+#include "halmips.h"
+
+//
+// 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
+// HalFlushDcachePage (
+// 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(HalFlushDcachePage)
+
+#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 HalFlushDcachePage
+
+ SBTTL("Purge Data Cache Page")
+//++
+//
+// VOID
+// HalPurgeDcachePage (
+// 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(HalPurgeDcachePage)
+
+#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 HalPurgeDcachePage
+
+ SBTTL("Purge Instruction Cache Page")
+//++
+//
+// VOID
+// HalPurgeIcachePage (
+// 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(HalPurgeIcachePage)
+
+#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 HalPurgeIcachePage
+
+ SBTTL("Sweep Data Cache")
+//++
+//
+// VOID
+// HalSweepDcache (
+// VOID
+// )
+//
+// Routine Description:
+//
+// This function sweeps (index/writeback/invalidate) the entire data cache.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalSweepDcache)
+
+#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)
+ 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 HalSweepDcache
+
+ 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
+// HalSweepIcache (
+// VOID
+// )
+//
+// Routine Description:
+//
+// This function sweeps (index/invalidate) the entire instruction cache.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalSweepIcache)
+
+#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)
+ 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 HalSweepIcache
+
+ 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
+// HalZeroPage (
+// 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(HalZeroPage, 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
+ mtc1 zero,f0 // set write pattern
+ mtc1 zero,f1 //
+ 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.
+//
+
+#if defined(_MULTI_)
+
+30: 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,30b // if ne, more to zero
+ sdc1 f0,-8(t0) //
+
+#else
+
+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
+
+#endif
+
+ .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
+
+#if defined(_MULTI_)
+
+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) //
+
+#else
+
+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
+
+#endif
+
+ .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 HalZeroPage
diff --git a/private/ntos/nthals/halsni4x/mips/j4flshbf.s b/private/ntos/nthals/halsni4x/mips/j4flshbf.s
new file mode 100644
index 000000000..2b6978d6c
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/j4flshbf.s
@@ -0,0 +1,53 @@
+#if defined(R4000)
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk35/src/hal/halsni/mips/RCS/j4flshbf.s,v 1.1 1994/10/13 15:47:06 holli 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/halsni4x/mips/j4flshio.c b/private/ntos/nthals/halsni4x/mips/j4flshio.c
new file mode 100644
index 000000000..93ae1123d
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/j4flshio.c
@@ -0,0 +1,202 @@
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk35/src/hal/halsni/mips/RCS/j4flshio.c,v 1.2 1994/12/01 15:18:29 holli 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 MIPS R4000 Jazz, Fision, Fusion,
+ or Duo system.
+
+
+--*/
+
+#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 Jazz R4000 uses 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 or
+ // purge 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 operation, then purge the
+ // data cache. Otherwise, is the I/O operation is a page read
+ // operation, then flush the data cache.
+ //
+
+ if (DmaOperation != FALSE) {
+ HalPurgeDcachePage((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/halsni4x/mips/j4prof.c b/private/ntos/nthals/halsni4x/mips/j4prof.c
new file mode 100644
index 000000000..1f76f3616
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/j4prof.c
@@ -0,0 +1,325 @@
+/*++
+
+Copyright (c) 1991-1994 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.
+
+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 = RtlConvertUlongToLargeInteger(HalpProfileCountRate);
+ }
+
+ //
+ // Return the value of the performance counter.
+ //
+
+ return RtlLargeIntegerAdd(PerformanceCounter,
+ RtlConvertUlongToLargeInteger(CurrentCount));
+}
+
+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.
+
+--*/
+
+{
+
+ KSPIN_LOCK Lock;
+ KIRQL OldIrql;
+ PKPRCB Prcb;
+
+ //
+ // Raise IRQL to HIGH_LEVEL, decrement the number of processors, and
+ // wait until the number is zero.
+ //
+
+ KeInitializeSpinLock(&Lock);
+ KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+ if (ExInterlockedDecrementLong(Number, &Lock) != 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].LowPart = 0;
+ HalpPerformanceCounter[Prcb->Number].HighPart = 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 = RtlLargeIntegerAdd(TempValue,
+ RtlConvertUlongToLargeInteger(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 Reserved
+ )
+
+/*++
+
+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:
+
+ None.
+
+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 = RtlLargeIntegerAdd(TempValue,
+ RtlConvertUlongToLargeInteger(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] =
+ RtlLargeIntegerAdd(HalpPerformanceCounter[Prcb->Number],
+ RtlConvertUlongToLargeInteger(PreviousCount));
+
+ return;
+}
+
+VOID
+HalStopProfileInterrupt (
+ KPROFILE_SOURCE Reserved
+ )
+
+/*++
+
+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:
+
+ None.
+
+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] =
+ RtlLargeIntegerAdd(HalpPerformanceCounter[Prcb->Number],
+ RtlConvertUlongToLargeInteger(PreviousCount));
+
+ return;
+}
diff --git a/private/ntos/nthals/halsni4x/mips/jxbeep.c b/private/ntos/nthals/halsni4x/mips/jxbeep.c
new file mode 100644
index 000000000..13d80a99c
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/jxbeep.c
@@ -0,0 +1,132 @@
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk35/src/hal/halsni/mips/RCS/jxbeep.c,v 1.1 1994/10/13 15:47:06 holli 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/halsni4x/mips/jxebsup.c b/private/ntos/nthals/halsni4x/mips/jxebsup.c
new file mode 100644
index 000000000..48f523bb9
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/jxebsup.c
@@ -0,0 +1,2851 @@
+#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk35/src/hal/halsni/mips/RCS/jxebsup.c,v 1.3 1995/04/07 09:56:05 flo 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,
+ IN ULONG noncachedAddress
+ );
+
+
+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.
+ //
+
+ if (NumberOfMapRegisters != 0 && AdapterObject->NeedsMapRegisters) {
+
+ //
+ // 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) {
+
+ 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) {
+
+ //
+ // 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->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(HalpEisaExtensionInstalled && (DeviceDescriptor->InterfaceType != Internal)) {
+ controlBase = (PEISA_CONTROL)HalpEisaControlBase;
+ } else
+
+
+ //
+ // If we have no Eisa Extension installed 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 ((HalpBusType == MACHINE_TYPE_EISA) && (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.
+ //
+
+ if(HalpEisaExtensionInstalled && (DeviceDescriptor->InterfaceType != Internal))
+ tmpAdapterObject = HalpEisaAdapter[DeviceDescriptor->DmaChannel];
+ else
+ 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) {
+
+ if(HalpEisaExtensionInstalled && (DeviceDescriptor->InterfaceType != Internal))
+ HalpEisaAdapter[DeviceDescriptor->DmaChannel] = adapterObject;
+ else
+ 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 noncachedAddress;
+ ULONG partialLength;
+ ULONG temp;
+ PEISA_CONTROL controlBase;
+
+
+ if(AdapterObject !=NULL && HalpEisaExtensionInstalled && (AdapterObject->InterfaceType != Internal)) {
+ controlBase = (PEISA_CONTROL)HalpEisaControlBase;
+ } else
+
+ // 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.
+ //
+
+ if (HalpBusType == MACHINE_TYPE_EISA) {
+
+ while( transferLength < *Length ){
+
+ if (*pageFrame + 1 != *(pageFrame + 1)) {
+ break;
+ }
+
+ transferLength += PAGE_SIZE;
+ pageFrame++;
+
+ }
+
+ } else {
+
+ while( transferLength < *Length ){
+
+ if (*pageFrame + 1 != *(pageFrame + 1) ||
+ (*pageFrame & ~0x0f) != (*(pageFrame + 1) & ~0x0f)) {
+ 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 ) {
+
+ noncachedAddress = KSEG1_BASE | ((*pageFrame << PAGE_SHIFT) + BYTE_OFFSET(CurrentVa));
+
+ HalpCopyBufferMap(
+ Mdl,
+ translationEntry + index,
+ CurrentVa,
+ partialLength,
+ WriteToDevice,
+ noncachedAddress
+ );
+
+ (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) {
+
+ noncachedAddress = KSEG1_BASE | ((*pageFrame << PAGE_SHIFT) + BYTE_OFFSET(CurrentVa));
+
+ HalpCopyBufferMap(
+ Mdl,
+ translationEntry + index,
+ CurrentVa,
+ partialLength,
+ WriteToDevice,
+ noncachedAddress
+ );
+
+ }
+
+ 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]
+ );
+
+ if (HalpBusType == MACHINE_TYPE_EISA) {
+
+ //
+ // 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]
+ );
+
+ if (HalpBusType == MACHINE_TYPE_EISA) {
+
+ //
+ // 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;
+ ULONG logicalAddress;
+ ULONG noncachedAddress;
+
+ ULONG PagesAbove16MB;
+ ULONG PagesBelow16MB;
+
+ 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 ){
+
+ logicalAddress = (*pageFrame << PAGE_SHIFT) + BYTE_OFFSET(CurrentVa);
+ noncachedAddress = KSEG1_BASE | logicalAddress;
+
+ HalpCopyBufferMap(
+ Mdl,
+ translationEntry,
+ CurrentVa,
+ partialLength,
+ WriteToDevice,
+ noncachedAddress
+ );
+
+ (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) {
+
+ logicalAddress = (*pageFrame << PAGE_SHIFT) + BYTE_OFFSET(CurrentVa);
+ noncachedAddress = KSEG1_BASE | logicalAddress;
+
+ HalpCopyBufferMap(
+ Mdl,
+ translationEntry,
+ CurrentVa,
+ partialLength,
+ WriteToDevice,
+ noncachedAddress
+ );
+
+ }
+ }
+
+ } 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;
+
+ PagesBelow16MB = 0;
+ PagesAbove16MB = 0;
+
+ while( transferLength <= Length ){
+
+ if (*pageFrame >= BYTES_TO_PAGES(MAXIMUM_PHYSICAL_ADDRESS)) {
+
+ logicalAddress = (*pageFrame << PAGE_SHIFT) + BYTE_OFFSET(CurrentVa);
+ noncachedAddress = KSEG1_BASE | logicalAddress;
+
+ HalpCopyBufferMap(
+ Mdl,
+ translationEntry,
+ CurrentVa,
+ partialLength,
+ WriteToDevice,
+ noncachedAddress
+ );
+
+ PagesAbove16MB++;
+
+ }
+
+ else {
+
+ PagesBelow16MB++;
+
+ }
+
+ (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)) {
+
+ logicalAddress = (*pageFrame << PAGE_SHIFT) + BYTE_OFFSET(CurrentVa);
+ noncachedAddress = KSEG1_BASE | logicalAddress;
+
+ HalpCopyBufferMap(
+ Mdl,
+ translationEntry,
+ CurrentVa,
+ partialLength,
+ WriteToDevice,
+ noncachedAddress
+ );
+
+ PagesAbove16MB++;
+
+ }
+
+ else {
+
+ PagesBelow16MB++;
+
+ }
+ }
+
+ }
+ }
+
+ //
+ // 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;
+
+
+ if (HalpEisaExtensionInstalled && (InterfaceType == Eisa) ) {
+
+ controlBase = (PEISA_CONTROL)HalpEisaControlBase;
+
+#ifdef NEVER
+
+ // we call this direct from the first level dispatcher ...
+
+ //
+ // Initialize the interrupt dispatcher for the EISA Extension board on an RM200
+ // (same Interrupt routine but different Acknowledge Address, this is told
+ // to HalpEisaDispatch via the ServiceContext Parameter)
+ //
+
+ KeInitializeInterrupt( &HalpEisaInterrupt,
+ HalpEisaDispatch,
+ (PVOID)EISA_CONTROL_PHYSICAL_BASE, // Service Context
+ (PKSPIN_LOCK)NULL,
+ EISA_VECTOR, // entry in IDT
+ EISA_DEVICE_LEVEL,
+ EISA_DEVICE_LEVEL, // Synchronization level
+ // EISA_DEVICE_LEVEL == SCSIEISA_LEVEL
+ // new SCSI Interrupt ???
+ LevelSensitive,
+ TRUE,
+ 0,
+ FALSE
+ );
+
+
+ if (!KeConnectInterrupt( &HalpEisaInterrupt )) {
+ return(FALSE);
+ }
+#endif
+
+ } else {
+
+ controlBase = (PEISA_CONTROL)HalpOnboardControlBase;
+
+#ifdef NEVER
+
+ // we call this direct from the first level dispatcher ...
+
+ //
+ // Initialize the interrupt dispatcher for onboard components
+ // in the PC core
+ //
+
+ KeInitializeInterrupt( &HalpOnboardInterrupt,
+ HalpEisaDispatch,
+ (PVOID)RM200_ONBOARD_CONTROL_PHYSICAL_BASE,// Service Context
+ (PKSPIN_LOCK)NULL,
+ ONBOARD_VECTOR, // entry in IDT
+ EISA_DEVICE_LEVEL,
+ EISA_DEVICE_LEVEL, // Synchronization level
+ // EISA_DEVICE_LEVEL == SCSIEISA_LEVEL
+ // new SCSI Interrupt ???
+ LevelSensitive,
+ TRUE,
+ 0,
+ FALSE
+ );
+
+
+ if (!KeConnectInterrupt( &HalpOnboardInterrupt )) {
+ return(FALSE);
+ }
+#endif
+
+ }
+
+ //
+ // 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
+ );
+
+
+ if (HalpEisaExtensionInstalled && (InterfaceType == Eisa)) {
+
+ //
+ // this is for the EISA Extension board
+ // Disable all of the interrupts except the slave.
+ //
+
+ HalpEisaInterrupt1Mask = (UCHAR) ~(1 << SLAVE_IRQL_LEVEL);
+
+ WRITE_REGISTER_UCHAR(
+ &(controlBase)->Interrupt1ControlPort1,
+ HalpEisaInterrupt1Mask
+ );
+
+ HalpEisaInterrupt2Mask = 0xFF;
+
+ WRITE_REGISTER_UCHAR(
+ &(controlBase)->Interrupt2ControlPort1,
+ HalpEisaInterrupt2Mask
+ );
+
+ //
+ // Initialize the edge/level register masks to 0 which is the default
+ // edge sensitive value.
+ //
+
+ HalpEisaInterrupt1Level = 0;
+ HalpEisaInterrupt2Level = 0;
+
+ } else {
+
+ //
+ // 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;
+
+ } // closing if statement
+
+ //
+ // 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
+HalpEisaDispatch(
+ 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 service routine should be connected as follows:
+
+ KeInitializeInterrupt(&Interrupt, HalpEisaDispatch,
+ EISA_VIRTUAL_BASE,
+ (PKSPIN_LOCK)NULL, EISA_LEVEL, EISA_LEVEL, EISA_LEVEL,
+ LevelSensitive, TRUE, 0, FALSE);
+ KeConnectInterrupt(&Interrupt);
+
+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;
+ PUCHAR InterruptAckAddr;
+ BOOLEAN returnValue;
+ PEISA_CONTROL controlBase;
+
+
+
+ if(HalpEisaExtensionInstalled && ((ULONG)ServiceContext == EISA_CONTROL_PHYSICAL_BASE)){
+
+ //
+ // this is when the Eisa Extension is installed
+ //
+
+ controlBase = (PEISA_CONTROL)HalpEisaControlBase;
+ InterruptAckAddr = (HalpIsRM200) ?
+ (PUCHAR)RM200_EISA_INT_ACK_REGISTER:
+ (PUCHAR)RM400_EISA_INT_ACK_REGISTER;
+ PCRInOffset = EISA_VECTORS;
+
+ } else {
+
+ PCRInOffset = ONBOARD_VECTORS;
+ controlBase = (PEISA_CONTROL)HalpOnboardControlBase;
+ InterruptAckAddr = (HalpIsRM200) ?
+ (PUCHAR)RM200_ONBOARD_INT_ACK_REGISTER:
+ (PUCHAR)RM400_ONBOARD_INT_ACK_REGISTER;
+
+ }
+
+ //
+ // start an 80x86 Interrupt Ack cycle by the SNI Hardware and reset the
+ // bit in the chipset
+ //
+
+ interruptVector =READ_REGISTER_UCHAR(InterruptAckAddr);
+
+ PCRInOffset += (USHORT) (interruptVector & ~0x80);
+
+ //
+ // Dispatch to the secondary interrupt service routine.
+ //
+
+ returnValue = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[PCRInOffset])(
+ PCR->InterruptRoutine[PCRInOffset]
+ );
+
+ if (interruptVector & 0x08) {
+
+ //
+ // The interrupt was on controler 2
+ // Clear the interrupt from Interrupt Controller 2
+ //
+
+ WRITE_REGISTER_UCHAR(
+ &(controlBase)->Interrupt2ControlPort0,
+ NONSPECIFIC_END_OF_INTERRUPT
+ );
+
+ }
+
+ //
+ // The interrupt was on controler 1
+ //
+
+ WRITE_REGISTER_UCHAR(
+ &(controlBase)->Interrupt1ControlPort0,
+ NONSPECIFIC_END_OF_INTERRUPT
+ );
+
+ return returnValue;
+
+}
+
+#ifdef NEVER
+
+BOOLEAN
+HalpEisaDispatch_OK(
+ 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 service routine should be connected as follows:
+
+ KeInitializeInterrupt(&Interrupt, HalpEisaDispatch,
+ EISA_VIRTUAL_BASE,
+ (PKSPIN_LOCK)NULL, EISA_LEVEL, EISA_LEVEL, EISA_LEVEL,
+ LevelSensitive, TRUE, 0, FALSE);
+ KeConnectInterrupt(&Interrupt);
+
+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;
+ UCHAR IntRequest;
+ ULONG i;
+ USHORT PCRInOffset, Offset;
+ BOOLEAN returnValue;
+ PEISA_CONTROL controlBase;
+
+
+
+ if(HalpEisaExtensionInstalled && ((ULONG)ServiceContext == EISA_CONTROL_PHYSICAL_BASE)){
+
+ //
+ // this was an interrupt in the Eisa backplane
+ //
+
+ controlBase = (PEISA_CONTROL)HalpEisaControlBase;
+ PCRInOffset = EISA_VECTORS;
+ Offset = EISA_VECTORS;
+
+ } else {
+
+ //
+ // 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;
+
+ }
+ }
+ }
+}
+#endif
diff --git a/private/ntos/nthals/halsni4x/mips/jxenvirv.c b/private/ntos/nthals/halsni4x/mips/jxenvirv.c
new file mode 100644
index 000000000..15a057425
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/jxenvirv.c
@@ -0,0 +1,192 @@
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk35/src/hal/halsni/mips/RCS/jxenvirv.c,v 1.1 1994/10/13 15:47:06 holli 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/halsni4x/mips/jxhwsup.c b/private/ntos/nthals/halsni4x/mips/jxhwsup.c
new file mode 100644
index 000000000..07f6d5bc2
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/jxhwsup.c
@@ -0,0 +1,2437 @@
+#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk351/src/hal/halsni4x/mips/RCS/jxhwsup.c,v 1.1 1995/05/19 11:19:03 flo 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();
+
+ULONG
+HalpReadEisaData (
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+IO_ALLOCATION_ACTION
+HalpAllocationRoutine (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ );
+
+//
+// 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.
+
+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;
+
+ 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.
+ //
+ 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;
+
+ }
+
+ //
+ // Initialize the map registers where memory has been allocated.
+ //
+
+ TranslationEntry = ((PTRANSLATION_ENTRY) AdapterObject->MapRegisterBase) +
+ AdapterObject->NumberOfMapRegisters;
+
+ for (i = 0; i < NumberOfPages; i++) {
+
+ //
+ // 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++;
+ }
+
+ //
+ // 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,
+ IN ULONG noncachedAddress
+ )
+
+/*++
+
+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)noncachedAddress, Length);
+
+ } else {
+
+ RtlMoveMemory( (PCCHAR)noncachedAddress, mapAddress, Length);
+
+
+ }
+
+}
+
+IO_ALLOCATION_ACTION
+HalpAllocationRoutine (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called by HalAllocateAdapterChannel when sufficent resources
+ are available to the driver. This routine saves the MapRegisterBase,
+ and set the event pointed to by the context parameter.
+
+Arguments:
+
+ DeviceObject - Supplies a pointer where the map register base should be
+ stored.
+
+ Irp - Unused.
+
+ MapRegisterBase - Supplied by the Io subsystem for use in IoMapTransfer.
+
+ Context - Supplies a pointer to an event which is set to indicate the
+ AdapterObject has been allocated.
+
+Return Value:
+
+ DeallocateObjectKeepRegisters - Indicates the adapter should be freed
+ and mapregisters should remain allocated after return.
+
+--*/
+
+{
+
+ UNREFERENCED_PARAMETER(Irp);
+
+ *((PVOID *) DeviceObject) = MapRegisterBase;
+
+ (VOID) KeSetEvent( (PKEVENT) Context, 0L, FALSE );
+
+ return(DeallocateObjectKeepRegisters);
+}
+
+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 == -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;
+ PVOID mapRegisterBase;
+ ULONG numberOfMapRegisters;
+ ULONG mappedLength;
+ WAIT_CONTEXT_BLOCK wcb;
+ KEVENT allocationEvent;
+ NTSTATUS status;
+ PMDL mdl;
+ KIRQL irql;
+ PTRANSLATION_ENTRY MapRegisterTranslation;
+
+ numberOfMapRegisters = BYTES_TO_PAGES(Length);
+
+ //
+ // Allocate the actual buffer.
+ //
+
+ if (CacheEnabled != FALSE) {
+ virtualAddress = ExAllocatePool(NonPagedPoolCacheAligned, Length);
+
+ } else {
+ MapRegisterTranslation = HalpAcquireMapBuffers(numberOfMapRegisters,MasterAdapterObject);
+ if (MapRegisterTranslation == NULL) return(NULL);
+ virtualAddress = MapRegisterTranslation->VirtualAddress;
+ LogicalAddress->LowPart = MapRegisterTranslation->PhysicalAddress;
+ LogicalAddress->HighPart = 0;
+ KeStallExecutionProcessor(50000);
+ return(virtualAddress);
+ }
+
+
+ if (virtualAddress == NULL) {
+ return(virtualAddress);
+
+ }
+
+ //
+ // Initialize an event.
+ //
+
+ KeInitializeEvent( &allocationEvent, NotificationEvent, FALSE);
+
+ //
+ // Initialize the wait context block. Use the device object to indicate
+ // where the map register base should be stored.
+ //
+
+ wcb.DeviceObject = &mapRegisterBase;
+ wcb.CurrentIrp = NULL;
+ wcb.DeviceContext = &allocationEvent;
+
+ //
+ // Allocate the adapter and the map registers.
+ //
+
+ KeRaiseIrql(DISPATCH_LEVEL, &irql);
+
+ status = HalAllocateAdapterChannel(
+ AdapterObject,
+ &wcb,
+ numberOfMapRegisters,
+ HalpAllocationRoutine
+ );
+
+ KeLowerIrql(irql);
+
+ if (!NT_SUCCESS(status)) {
+
+ //
+ // Cleanup and return NULL.
+ //
+
+ if (CacheEnabled != FALSE) {
+ ExFreePool(virtualAddress);
+
+ } else {
+ MmFreeNonCachedMemory(virtualAddress, Length);
+ }
+
+ return(NULL);
+
+ }
+
+ //
+ // Wait for the map registers to be allocated.
+ //
+
+ status = KeWaitForSingleObject(
+ &allocationEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status)) {
+
+ //
+ // Cleanup and return NULL.
+ //
+
+ if (CacheEnabled != FALSE) {
+ ExFreePool(virtualAddress);
+
+ } else {
+ MmFreeNonCachedMemory(virtualAddress, Length);
+ }
+
+ return(NULL);
+
+ }
+
+ //
+ // Create an mdl to use with call to I/O map transfer.
+ //
+
+ mdl = IoAllocateMdl(
+ virtualAddress,
+ Length,
+ FALSE,
+ FALSE,
+ NULL
+ );
+
+ MmBuildMdlForNonPagedPool(mdl);
+
+ //
+ // Map the transfer so that the controller can access the memory.
+ //
+
+ mappedLength = Length;
+ *LogicalAddress = IoMapTransfer(
+ NULL,
+ mdl,
+ mapRegisterBase,
+ virtualAddress,
+ &mappedLength,
+ TRUE
+ );
+
+ IoFreeMdl(mdl);
+
+ if (mappedLength < Length) {
+
+ //
+ // Cleanup and indicate that the allocation failed.
+ //
+
+ HalFreeCommonBuffer(
+ AdapterObject,
+ Length,
+ *LogicalAddress,
+ virtualAddress,
+ CacheEnabled
+ );
+
+ return(NULL);
+ }
+
+ //
+ // The allocation completed successfully.
+ // for some reason, we have to pause if we have the onboard scsi controller AND
+ // an Adaptec AHA1740 Eisa SCSI controller ...
+ // trial and error ...
+ //
+
+ KeStallExecutionProcessor(50000);
+
+ //
+ // The allocation completed successfully.
+ //
+
+ 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 i;
+
+ //
+ // Free the memory for the common buffer.
+ //
+
+ if (CacheEnabled != FALSE) {
+
+ ExFreePool(VirtualAddress);
+
+ } else {
+
+// MmFreeNonCachedMemory(VirtualAddress, Length);
+// if(AdapterObject->NeedsMapRegisters == FALSE) 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;
+}
+#ifdef NEVER
+
+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 memory 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;
+ PHYSICAL_ADDRESS physicalAddress;
+
+ UNREFERENCED_PARAMETER(AdapterObject);
+ UNREFERENCED_PARAMETER(CacheEnabled);
+
+ // Because we support ISA devices, and they cannot reference
+ // past 16MB of memory, we must make sure that the contiguous
+ // memory we allocate is below 16Mb.
+
+ physicalAddress.LowPart = MAXIMUM_PHYSICAL_ADDRESS -1;
+ physicalAddress.HighPart = 0;
+
+
+ //
+ // Allocate the actual buffer.
+ //
+
+ virtualAddress = MmAllocateContiguousMemory(
+ Length,
+ physicalAddress
+ );
+
+ DbgPrint("MmAllocateContiguousMemory returns 0x%x ... \n", virtualAddress);
+
+ if (!HALP_IS_PHYSICAL_ADDRESS(virtualAddress)) {
+
+ *LogicalAddress = MmGetPhysicalAddress(virtualAddress);
+
+ } else {
+
+ *LogicalAddress = RtlConvertUlongToLargeInteger(
+ (ULONG)virtualAddress &
+ (~KSEG0_BASE)
+ );
+
+ }
+ return((PVOID)((ULONG)virtualAddress | KSEG1_BASE));
+}
+
+
+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.
+
+--*/
+
+{
+
+ UNREFERENCED_PARAMETER(AdapterObject);
+ UNREFERENCED_PARAMETER(Length);
+ UNREFERENCED_PARAMETER(LogicalAddress);
+ UNREFERENCED_PARAMETER(VirtualAddress);
+
+ 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
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(AdapterObject);
+ UNREFERENCED_PARAMETER(Length);
+ UNREFERENCED_PARAMETER(LogicalAddress);
+ UNREFERENCED_PARAMETER(CacheEnabled);
+
+ MmFreeContiguousMemory((PVOID)(((ULONG)VirtualAddress & (~KSEG1_BASE)) | KSEG0_BASE));
+
+
+}
+
+#endif
+
+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 != 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 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;
+
+ 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
+
+--*/
+{
+ //
+ // This HAL doesn't support any buses which support
+ // HalAssignSlotResources
+ //
+
+ return STATUS_NOT_SUPPORTED;
+
+}
+
+NTSTATUS
+HalAdjustResourceList (
+ IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList
+// IN OUT PVOID Argument0
+ )
+/*++
+
+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
+
+--*/
+{
+ //
+ // 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/halsni4x/mips/jxmapio.c b/private/ntos/nthals/halsni4x/mips/jxmapio.c
new file mode 100644
index 000000000..482a287f3
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/jxmapio.c
@@ -0,0 +1,133 @@
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk35/src/hal/halsni/mips/RCS/jxmapio.c,v 1.1 1994/10/13 15:47:06 holli 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);
+PVOID HalpOnboardControlBase=(PVOID) (RM200_ONBOARD_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);
+
+ //
+ // for the sni deskop model, may need an extra address space
+ // HalpEisaExtensionInstalled can only be TRUE on RM200 (Desktop)
+ //
+
+ if (HalpEisaExtensionInstalled) {
+ physicalAddress.HighPart = 0;
+ physicalAddress.LowPart = RM200_ONBOARD_CONTROL_PHYSICAL_BASE;
+ HalpOnboardControlBase = MmMapIoSpace(physicalAddress,
+ PAGE_SIZE * 16,
+ FALSE);
+
+ } else
+
+ //
+ // In the SNI Minitower model, we have only one
+ // address space
+ //
+
+ 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/halsni4x/mips/jxport.c b/private/ntos/nthals/halsni4x/mips/jxport.c
new file mode 100644
index 000000000..11b17a6d6
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/jxport.c
@@ -0,0 +1,805 @@
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk35/src/hal/halsni/mips/RCS/jxport.c,v 1.2 1995/02/13 12:49:39 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/halsni4x/mips/jxreturn.c b/private/ntos/nthals/halsni4x/mips/jxreturn.c
new file mode 100644
index 000000000..7999a2690
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/jxreturn.c
@@ -0,0 +1,239 @@
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk35/src/hal/halsni/mips/RCS/jxreturn.c,v 1.3 1995/02/13 12:49:56 flo 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
+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;
+ PUCHAR MachineControlRegister = (HalpIsRM200) ?
+ (PUCHAR) RM200_MCR_ADDR :
+ (PUCHAR) RM400_MCR_ADDR;
+
+ //
+ // Disable Interrupts.
+ //
+ KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+
+ //
+ // Case on the type of return.
+ //
+
+ switch (Routine) {
+ case HalHaltRoutine:
+
+ //
+ // Hang looping.
+ //
+ for (;;) {}
+
+ case HalPowerDownRoutine:
+
+ //
+ // PowerOff is done by the SNI machines by writing the Power_Off bit to the machine control register ...
+ //
+
+ WRITE_REGISTER_UCHAR(MachineControlRegister, MCR_POWER_OFF);
+ for (;;) {} // hang looping
+
+
+ case HalRestartRoutine:
+ case HalRebootRoutine:
+ case HalInteractiveModeRoutine:
+
+
+ if (HalpIsMulti) {
+ ULONG Mask;
+
+ Mask = HalpActiveProcessors & ~(PCR->SetMember);
+#if DBG
+ DbgPrint("Send message RESTART to maskcpu = %x \n",Mask);
+#endif
+
+ HalpSendIpi(Mask,MPA_RESTART_MESSAGE);
+ //
+ // if this is not the Boot CPU, we call a special Firmware entry to stop it
+ //
+
+ if (PCR->Number ) {
+ //
+ // remove this processor from the list of active processors
+ //
+ HalpActiveProcessors &= (~(PCR->SetMember));
+
+ HalSweepDcache(); // this should run only local ...
+#if DBG
+ DbgPrint(" Reinit slave %x \n", ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->reinit_slave);
+#endif
+ ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->reinit_slave();
+
+ } else HalpBootCpuRestart();
+ }
+
+
+ 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
+ );
+
+ if (HalpIsRM200) {
+
+ //
+ // Reset the SNI RM200 machines by writing the reset bit to the machine control register ...
+ // ArcReboot does not work correctly on the RM200 (Reset of the Isa Bus)
+ //
+
+ WRITE_REGISTER_UCHAR(MachineControlRegister, (MCR_INRESET | MCR_PODD));
+
+ } else {
+
+ 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;
+
+ cpt = 0;
+ while(HalpActiveProcessors != PCR->SetMember) {
+ KeStallExecutionProcessor(500000);
+ ++cpt;if (cpt == 20) break;
+ }
+ //
+ // if there are still ssome processors active, we do a reset of the entire machine
+ //
+ if (HalpActiveProcessors != PCR->SetMember) {
+
+#if DBG
+ DbgPrint(" Some processors did not answer (%x). Reset machine started. \n", HalpActiveProcessors);
+#endif
+ WRITE_REGISTER_UCHAR((PUCHAR) RM400_MCR_ADDR, (MCR_INRESET | MCR_PODD));
+
+ } 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/halsni4x/mips/jxsysint.c b/private/ntos/nthals/halsni4x/mips/jxsysint.c
new file mode 100644
index 000000000..ee70178da
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/jxsysint.c
@@ -0,0 +1,380 @@
+#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk351/src/hal/halsni4x/mips/RCS/jxsysint.c,v 1.1 1995/05/19 11:20:52 flo 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) {
+
+ if (HalpIsRM200)
+ //
+ // the RM200 has an Opti 499 Chip, which is an "real" Isa Chipset
+ // so we cannot support Level sensitive Interrupts ...
+ //
+
+ HalpEnableOnboardInterrupt( Vector, Latched);
+ else
+ 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);
+ }
+
+ //
+ // these are the "real" Onboard components (scsi and Ethernet)
+ // Return the passed parameters.
+ //
+
+ *Irql = (KIRQL) BusInterruptLevel;
+
+ //
+ // this is the special case of the onboard Ethernet Controller
+ // At CPU Modules with an R4400 PC this goes directly to corresponding
+ // Cause Register Bit IP7 (bad bad ..)
+ // on MUltiPro machines this IP7 is used for IPI Interrupts so we have to
+ // manipulate this.
+ //
+
+ if (BusInterruptVector == NET_DEFAULT_VECTOR){
+
+ extern BOOLEAN HalpProcPc;
+ //
+ // the RM200 and all SC machines have a central Device Interrupt
+ // which is software managed by this HAL ...
+ // leave al other cases as they are ...
+ //
+
+ if ( ((HalpProcPc == FALSE) && (HalpProcessorId != ORIONSC)) || (HalpMainBoard==M8036)) {
+
+ if (HalpProcessorId == MPAGENT) {
+
+ BusInterruptVector = NET_LEVEL;
+ *Irql = (KIRQL) NETMULTI_LEVEL;
+ *Affinity = 1 << HalpNetProcessor; // proc 1 if started
+
+ } else {
+
+ BusInterruptVector = NET_LEVEL;
+
+ //
+ // Irql is equal to the most common Device Interrupt Level
+ // (currently 4)
+ //
+
+ *Irql = (KIRQL) SCSIEISA_LEVEL;
+ }
+
+ }
+
+ return ( BusInterruptVector);
+ }
+
+ //
+ // this is another special case of the EIP Interrupt for RM400 Tower
+ // we have an agreement with the EIP developer
+ // we meet each other on InterruptVector 15, so we limit the Irql to Device Level
+ //
+
+ if ( (HalpMainBoard==M8032) && (BusInterruptVector == EIP_VECTOR) ){
+
+ //
+ // Irql is equal to the most common Device Interrupt Level
+ // (currently 4)
+ //
+
+ if (HalpProcessorId == MPAGENT) *Irql = (KIRQL) INT3_LEVEL; else *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;
+ }
+
+ //
+ // The vector is equal to the specified bus level plus the ONBOARD/EISA_VECTORS.
+ // in any case the interrupt vector for Isa or Eisa card has to be on the
+ // Backplane, so if an Eisa Extension is installed this is an Eisa Interrupt
+ //
+
+ if (HalpEisaExtensionInstalled ) {
+ return( BusInterruptLevel + EISA_VECTORS);
+ } else
+
+ //
+ // if there is no Eisa Extension installed
+ // all Isa/Eisa Interrupts should be handled by the onboard PC core
+ //
+
+ return(BusInterruptLevel + ONBOARD_VECTORS);
+
+}
diff --git a/private/ntos/nthals/halsni4x/mips/jxtime.c b/private/ntos/nthals/halsni4x/mips/jxtime.c
new file mode 100644
index 000000000..0e156e5c8
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/jxtime.c
@@ -0,0 +1,334 @@
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk35/src/hal/halsni/mips/RCS/jxtime.c,v 1.1 1994/10/13 15:47:06 holli 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
+
+
+typedef struct _RealTimeClock {
+ struct rtc_mem {
+ UCHAR value;
+ UCHAR FILL0[3]; // byte-wide device
+ } Memory[RTC_NVRAM_SIZE]; // Non-volatile ram
+ UCHAR ControlRegister; // control register
+ UCHAR FILL1[3];
+} RealTimeClock, *PRealTimeClock;
+
+
+
+/* Smartwatch offset registers */
+
+#define REG_CENT_SECS 0
+#define REG_SECS 1
+#define REG_MINS 2
+#define REG_HOURS 3
+#define REG_DAY_W 4
+#define REG_DAY_M 5
+#define REG_MONTH 6
+#define REG_YEAR 7
+
+/* 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
+HalpWriteClockRegister(
+ IN UCHAR number
+ );
+
+UCHAR
+HalpReadClockRegister(
+ VOID
+ );
+
+VOID
+HalpWritePattern(
+ VOID
+ );
+
+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;
+ int i;
+ UCHAR tmp[8];
+ KIRQL oldIrql;
+
+ KeRaiseIrql(HIGH_LEVEL, &oldIrql);
+
+ // write the pattern to gain access to the smartwatch registers
+
+
+ HalpWritePattern();
+
+ // Read the 8 registers of smartwatch
+
+ for (i = 0; i < 8; i++)
+ tmp[i] = HalpReadClockRegister();
+
+ KeLowerIrql(oldIrql);
+
+ // Convert the contents of smartwatch registers into CSHORT
+
+
+ msecs = ( (CSHORT) bcd_to_dec(tmp[REG_CENT_SECS] & MASK_CENT_SECS) ) * 10;
+ secs = (CSHORT) bcd_to_dec(tmp[REG_SECS] & MASK_SECS);
+ mins = (CSHORT) bcd_to_dec(tmp[REG_MINS] & MASK_MINS);
+ hours = (CSHORT) bcd_to_dec(tmp[REG_HOURS] & MASK_HOURS);
+ daymonth = (CSHORT) bcd_to_dec(tmp[REG_DAY_M] & MASK_DAY_M);
+ dayweek = (CSHORT) bcd_to_dec(tmp[REG_DAY_W] & MASK_DAY_W);
+ month = (CSHORT) bcd_to_dec(tmp[REG_MONTH] & MASK_MONTH);
+ year = (CSHORT) bcd_to_dec(tmp[REG_YEAR] & MASK_YEAR);
+
+
+ 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.
+
+--*/
+
+{
+ UCHAR tmp[8];
+ KIRQL oldIrql;
+ UCHAR year, month, daymonth, dayweek, hours, mins, secs, msecs;
+ int i;
+
+
+ //
+ // 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;
+
+
+ tmp[REG_CENT_SECS] = (UCHAR) (dec_to_bcd(msecs/10) & MASK_CENT_SECS);
+ tmp[REG_SECS] = (UCHAR) (dec_to_bcd(secs) & MASK_SECS);
+ tmp[REG_MINS] = (UCHAR) (dec_to_bcd(mins) & MASK_MINS);
+ tmp[REG_HOURS] = (UCHAR) (dec_to_bcd(hours) & MASK_HOURS);
+ tmp[REG_DAY_W] = (UCHAR) (dec_to_bcd(dayweek) & MASK_DAY_W);
+ tmp[REG_DAY_M] = (UCHAR) (dec_to_bcd(daymonth) & MASK_DAY_M);
+ tmp[REG_MONTH] = (UCHAR) (dec_to_bcd(month) & MASK_MONTH);
+ tmp[REG_YEAR] = (UCHAR) (dec_to_bcd(year) & MASK_YEAR);
+
+ KeRaiseIrql(HIGH_LEVEL, &oldIrql);
+
+ // write the pattern to gain access to the smartwatch registers
+
+ HalpWritePattern();
+
+ // Write the 8 registers of smartwatch
+
+ for (i=0; i <8; i++)
+ HalpWriteClockRegister(tmp[i]);
+
+ KeLowerIrql(oldIrql);
+
+ return TRUE;
+
+}
+
+//
+// Write a BCD 2-digits number in the smartwatch
+// This is done one bit at a time, LSB first
+//
+
+VOID
+HalpWriteClockRegister(
+ IN UCHAR number
+ )
+{
+ PRealTimeClock rtc;
+ UCHAR i;
+
+ rtc = (HalpIsRM200) ? (PRealTimeClock )(RM200_REAL_TIME_CLOCK):
+ (PRealTimeClock )(RM400_REAL_TIME_CLOCK);
+
+ for (i = 1; i <= 8; i++) {
+ WRITE_REGISTER_UCHAR(&rtc->ControlRegister, number);
+ number = number >> 1; // next bit to write
+ }
+
+}
+
+//
+// Read a BCD 2-digits number in the smartwatch
+// This is done one bit at a time, LSB first
+//
+
+UCHAR
+HalpReadClockRegister(
+ VOID
+ )
+{
+ PRealTimeClock rtc;
+ UCHAR i;
+ UCHAR number;
+
+ rtc = (HalpIsRM200) ? (PRealTimeClock )(RM200_REAL_TIME_CLOCK):
+ (PRealTimeClock )(RM400_REAL_TIME_CLOCK);
+
+ for (i = 0, number = 0; i < 8; i++) {
+ number += (READ_REGISTER_UCHAR(&rtc->ControlRegister) & 0x01) << i; // Read a bit and shift it
+ }
+
+ return(number);
+}
+
+//
+// Write a pattern to gain access to the smartwatch registers
+// First we do 9 read's to reset the pointer
+//
+
+VOID
+HalpWritePattern(
+ VOID
+ )
+{
+
+ // Pattern to use before reading or writing
+
+ static UCHAR ClockPattern[4] = {0xc5,0x3a,0xa3,0x5c};
+
+ register UCHAR *pt;
+ register UCHAR i;
+
+ for (i = 0; i <= 8; i++) (VOID) HalpReadClockRegister();
+ for (i = 0, pt = ClockPattern; i < sizeof(ClockPattern); i++) HalpWriteClockRegister(*pt++);
+ for (i = 0, pt = ClockPattern; i < sizeof(ClockPattern); i++) HalpWriteClockRegister(*pt++);
+
+}
+
+
diff --git a/private/ntos/nthals/halsni4x/mips/jxusage.c b/private/ntos/nthals/halsni4x/mips/jxusage.c
new file mode 100644
index 000000000..cde6fd09e
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/jxusage.c
@@ -0,0 +1,47 @@
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk35/src/hal/halsni/mips/RCS/jxusage.c,v 1.1 1994/10/13 15:47:06 holli 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/halsni4x/mips/minidef.h b/private/ntos/nthals/halsni4x/mips/minidef.h
new file mode 100644
index 000000000..0e9e98eb7
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/minidef.h
@@ -0,0 +1,141 @@
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk35/src/hal/halsni/mips/RCS/minidef.h,v 1.2 1994/11/09 07:54:26 holli Exp $")
+/*+++
+
+Copyright (c) 1993-1994 Siemens Nixdorf Informationssysteme AG
+
+Module Name:
+
+ MINIdef.h
+
+Abstract:
+
+ This file describes hardware addresses
+ for SNI Minitower and RM400-Tower which are not common
+ to all SNI machines.
+
+
+
+---*/
+
+#ifndef _MINIDEF_
+#define _MINIDEF_
+
+//
+// define various masks for the interrupt sources register
+//
+
+/*
+ The interrupt Source Register on an MiniTower has the following bits:
+
+ 7 6 5 4 3 2 1 0
+ +-------------------------------+
+ | 1 | 0 | 1 | 0 | 0 | x | 0 | 0 | 0 Low Activ; 1 High activ; x not connected
+ +-------------------------------+
+ |________ EISA/ ISA Interrupt (HalpEisaDispatch)
+ |____________ SCSI Interrupt (SCSI Driver)
+ |________________ EIP Interrupt (RM400 Tower Only/ Unused on Minitower)
+ |____________________ Timer 0 (HalpClockInterrupt1 on MULTI)
+ |________________________ Timer 1 (unused)
+ |____________________________ Ethernet (Net driver)
+ |________________________________ Push Button/Timeouts (HalpInt0Dispatch or HalpInt1Dispatch)
+ |____________________________________ Irq 9 (unused)
+
+ 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 | 0 | 0 | 0 | 1 | 1 | 0 Low Activ; 1 High activ; x not connected
+ +-------------------------------+
+ |________ ColdStart (unused)
+ |____________ OverTemperature Int. (dismiss only / unused on Tower)
+ |________________ EIP Interrupt (RM400 Tower Only/ unused on Minitower)
+ |____________________ Timer 1 (unused)
+ |________________________ Timer 0 (HalpClockInterrupt1 on MULTI)
+ |____________________________ PushButton (HalpInt0Dispatch or HalpInt1Dispatch)
+ |________________________________ Timeouts (HalpInt0Dispatch or HalpInt1Dispatch)
+ |____________________________________ not connected (unused)
+*/
+
+#define RM400_EISA_MASK 0x01 // these are the interrupts from the Eisa PC core
+#define RM400_SCSI_MASK 0x02
+#define RM400_SCSI_EISA_MASK 0x03
+#define RM400_NET_MASK 0x20
+#define RM400_PB_MASK 0x40
+#define RM400_MSR_TEMP_MASK 0x02 // OverTemperature Interrupt in the MSR (RM400MT only) (high active)
+#define RM400_MSR_EIP_MASK 0x04 // EIP Interrupt in the MSR (RM400 Tower only) (low active)
+#define RM400_MSR_TIMER0_MASK 0x10 // Timer 0 Interrupt in the MachineStatusRegister (low active)
+#define RM400_MSR_TIMER1_MASK 0x08 // Timer 1 Interrupt in the MachineStatusRegister (low active)
+#define RM400_MSR_PB_MASK 0x20 // PushButton is also reported in the MachineStatusRegister (low actice)
+#define RM400_MSR_TIMEOUT_MASK 0x40 // Timeout's are indicated in the MachineStatusRegister (low active)
+#define RM400_INTERRUPT_MASK 0x5f
+#define RM400_MSR_MASK 0xfc // 11111100 -> xor gives High active bits
+
+#define RM400_TOWER_EISA_MASK 0x01
+#define RM400_TOWER_SCSI_MASK 0x02
+#define RM400_TOWER_SCSI_EISA_MASK 0x03
+#define RM400_TOWER_EIP_MASK 0x04 // this is the famous EIP Interrupt ... (tower only)
+#define RM400_TOWER_NET_MASK 0x20
+#define RM400_TOWER_PB_MASK 0x40
+#define RM400_TOWER_TIMEOUT_MASK 0x40
+#define RM400_TOWER_INTERRUPT_MASK 0x5f
+
+#define RM400_ONBOARD_CONTROL_PHYSICAL_BASE EISA_CONTROL_PHYSICAL_BASE
+#define RM400_ONBOARD_MEMORY_PHYSICAL_BASE EISA_MEMORY_PHYSICAL_BASE
+#define RM400_ONBOARD_IO (ONBOARD_CONTROL_PHYSICAL_BASE | KSEG1_BASE)
+#define RM400_ONBOARD_MEMORY (ONBOARD_MEMORY_PHYSICAL_BASE | KSEG1_BASE)
+
+//
+// SNI ASIC registers
+//
+
+#define RM400_INTERRUPT_ACK_PHYSICAL_BASE 0x1c000000 // physical base of interrupt (ext. request) register
+#define RM400_INTERRUPT_ACK_REGISTER 0xbc000000 // physical base | KSEG1_BASE
+#define RM400_EISA_INT_ACK_PHYSICAL_BASE 0x1a000000 // physical base of EISA interrupt ack for the chipset
+#define RM400_EISA_INT_ACK_REGISTER 0xba000000 // physical base | KSEG1_BASE
+#define RM400_ONBOARD_INT_ACK_PHYSICAL_BASE RM400_EISA_INT_ACK_PHYSICAL_BASE // physical base of EISA interrupt ack for the chipset
+#define RM400_ONBOARD_INT_ACK_REGISTER RM400_EISA_INT_ACK_REGISTER // physical base | KSEG1_BASE
+#define RM400_INTERRUPT_SOURCE_PHYSICAL_BASE 0x1c020000 // physical base of interrupt source register
+#define RM400_INTERRUPT_SOURCE_REGISTER 0xbc020000 // physical base | KSEG1_BASE
+#define RM400_VESA_MAP_PHYSICAL_BASE 0x1c010000 // physical base of VLB map register
+#define RM400_VESA_MAP 0xbc010000 // physical base | KSEG1_BASE
+#define RM400_ISA_MAP_PHYSICAL_BASE 0x1c0e0000 // physical base of ISA map register (for BusMaster Devices)
+#define RM400_ISA_MAP 0xbc0e0000 // physical base | KSEG1_BASE
+
+#define RM400_LED_PHYSICAL_ADDR 0x1c090000 // LED Register physical
+#define RM400_LED_ADDR 0xbc090000 // LED Register | KSEG1_BASE
+#define RM400_MCR_PHYSICAL_ADDR 0x1c0b0000 // MachineConfigRegister
+#define RM400_MCR_ADDR 0xbc0b0000 // MachineConfigRegister | KSEG1
+#define RM400_MSR_PHYSICAL_ADDR 0x1c0a0000 // machine status register
+#define RM400_MSR_ADDR 0xbc0a0000 // machine status register | KSEG1
+
+//
+// System Timer (i82C54) and RealTimeClock Chip on RM400-10 and Minitower
+//
+
+#define RM400_TIMER0_MASK 0x10
+#define RM400_TIMER1_MASK 0x08
+#define RM400_TIMER_MASK 0x18 // Timer0 and Timer1
+#define RM400_EXTRA_TIMER_PHYSICAL_ADDR 0x1c040000 // physical base of Timer for system Clock
+#define RM400_EXTRA_TIMER_ADDR 0xbc040000 // Timer for system Clock |KSEG1_BASE
+#define RM400_TIMER0_ACK_ADDR 0xbc050000 // reset Timer0 Interrupt |KSEG1_BASE
+#define RM400_TIMER1_ACK_ADDR 0xbc060000 // reset Timer1 Interrupt |KSEG1_BASE
+
+#define RM400_NVRAM_PHYSICAL_BASE 0x1c080000 // physical base of nonvolatile RAM and RTC
+#define RM400_REAL_TIME_CLOCK_ADDRESS 0x1c080000 // physical base of RTC
+#define RM400_REAL_TIME_CLOCK 0xbc080000 // physical base of RTC | KSEG1_BASE
+#define RM400_RESET_DBG_BUT 0xbc0f0000 // reset debugger int | KSEG1_BASE
+#define RM400_RESET_TEMPBAT_INTR 0xbc0f0000 // reset Temperature/Battery int | KSEG1
+
+//
+// RM400 Tower (M8032)
+// specific Addresses
+//
+
+#define RM400_TOWER_INTERRUPT_SOURCE_PHYSICAL_BASE 0x1c010000 // physical base of interrupt source register
+#define RM400_TOWER_INTERRUPT_SOURCE_REGISTER 0xbc010000 // physical base | KSEG1_BASE
+#define RM400_TOWER_VESA0_MAP_PHYSICAL_BASE 0x1c0c0000 // physical base of Vesa Slot 0 map register
+#define RM400_TOWER_VESA0_MAP 0xbc0c0000 // physical base | KSEG1_BASE
+#define RM400_TOWER_VESA1_MAP_PHYSICAL_BASE 0x1c0d0000 // physical base of Vesa Slot 1 map register
+#define RM400_TOWER_VESA1_MAP 0xbc0d0000 // physical base | KSEG1_BASE
+
+#endif // _MINIDEF_
diff --git a/private/ntos/nthals/halsni4x/mips/mpagent.c b/private/ntos/nthals/halsni4x/mips/mpagent.c
new file mode 100644
index 000000000..7ea99caa1
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/mpagent.c
@@ -0,0 +1,681 @@
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk351/src/hal/halsni4x/mips/RCS/mpagent.c,v 1.1 1995/05/19 11:22:19 flo 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"
+
+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
+
+
+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;
+
+#if DBG
+ PCR->HalReserved[0] =0;
+#endif
+
+ //
+ // 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);
+
+ 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_IP5; /* send internal interrupts on external interrupt SR_IP5*/
+
+ 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); /* keep other fields */
+ 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
+ //
+
+ if (Number == 0) {
+
+ //
+ // For this release, the device interrupts are only processed by bootcpu.
+ //
+
+ reg |= (MPA_ENINT_SR_IP3
+ | MPA_ENINT_SR_IP4
+ | MPA_ENINT_SR_IP5
+// | MPA_ENINT_SR_IP6
+// | MPA_ENINT_SR_IP7
+ );
+
+ } else {
+
+ //
+ // place something special to non boot cpu here ...
+ //
+
+ reg |= (MPA_ENINT_SR_IP6 // Enable Extra Clock Interrupts (IP6)
+// | MPA_ENINT_SR_IP7
+ );
+ }
+
+ 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));
+
+ reg = ((MPAGENT_RESERVED & // put the reserved physical address (4Mb long)
+ MPA_OP_ADDR_MASK) |
+ MPA_OP_ENABLE); // enable the operator
+
+ WRITE_REGISTER_ULONG(&(mpagent->mem_operator), reg);
+
+}
+
+
+VOID
+HalpInit2MPAgent(
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the MutiProcessor_Agent chipset:
+ - enable net 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_IP7;
+
+ 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));
+
+ ++cpt ; NextRestartBlock = NextRestartBlock->NextRestartBlock;
+ }
+
+ HalpSendIpi(physmask,MPA_KERNEL_MESSAGE);
+
+}
+
+
+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;
+
+ 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
+ //
+
+ 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--);
+
+ if ((msg_status & MPA_VALSTAT) != MPA_VALSTAT) {
+
+#if DBG
+ DbgPrint("HAL: Watchdog Overrun !\n");
+#endif
+ KeStallExecutionProcessor(100);
+ 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 {
+
+#if DBGG
+ DbgPrint("HAL: Could not deliver IPI (busy)!\n");
+#endif
+ msg_retries = MPA_MSG_RETRY;
+ KeStallExecutionProcessor(100);
+ continue;
+ }
+
+ }
+
+
+ KeStallExecutionProcessor(10);
+
+ } while (--msg_retries); /* message aborted, try again */
+
+ KeLowerIrql(OldIrql);
+
+#if DBG
+ DbgPrint("HAL: WARNING - Could not deliver IPI (0x%x) MPA->status: 0x%2x! \n", msg_data, msg_status);
+ DbgPrint("HAL: pending Interupts: 0x%8x\n", READ_REGISTER_ULONG(&(mpagent->itpend)));
+#endif
+
+ 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) {
+
+ //
+ // reading the message register clears the interrupt from the MP Agent
+ //
+
+ msg_data = (READ_REGISTER_ULONG(&(mpagent->datamsg1)) >> 24);
+ HalpCheckSpuriousInt();
+
+ if (msg_data == MPA_KERNEL_MESSAGE) {
+ KeIpiInterrupt(TrapFrame);
+ return;
+ }
+
+ if (msg_data == MPA_RESTART_MESSAGE) {
+
+ if (PCR->Number) {
+
+#if DBGG
+ DbgPrint("Got shutdown message ...\n");
+#endif
+
+ // remove this processor from the list of active processors
+ HalpActiveProcessors &= (~(PCR->SetMember));
+
+ HalSweepDcache(); // flush the value above for the other processors
+
+ // 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 DBGG
+ DbgPrint("HAL: Warning: unknown IPI Interrupt Message in Register 1\n");
+#endif
+
+ }
+
+ 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();
+#if DBGG
+ DbgPrint("HAL: Got unexpected Interrupt in the MP Agent - \nnothing is pending [0x%08x] snooper 0x%08x cause: 0x%08x status: 0x%08xspurious = %d \n",
+ itpend, snooper, HalpGetCauseRegister(), HalpGetStatusRegister(),HalpCheckSpuriousInt());
+#endif
+
+ return;
+ }
+
+ if (itpend & MPA_INTN_MPBERR) {
+
+ //
+ // Fatal Error
+ //
+
+ ULONG snooper, cpureg ;
+
+#if DBGG
+ ULONG snpadreg, data, data2 ;
+ DbgPrint("HAL: FATAL - Fatal Error Interrupt in the MP Agent !!! \n");
+#endif
+
+ 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/
+
+#if DBGG
+ snpadreg = READ_REGISTER_ULONG(&(mpagent->snpadreg));
+ WRITE_REGISTER_ULONG( &(mpagent->tagreg),snpadreg);
+ data = READ_REGISTER_ULONG(&(mpagent->tagram));
+ data2 = HalpGetTaglo( data | KSEG0_BASE);
+ DbgPrint("snooper %08x Bad Address was: 0x%08x \nData in the Tag Copy is: 0x%08x\nData in the TagLo is: 0x%08x \n",snooper, snpadreg, data, data2);
+#endif
+
+ snooper |= MPA_RSTSNPERR; /* reset this MP_Agent fatal error */
+ WRITE_REGISTER_ULONG(&(mpagent->snooper), snooper); /* write the new value in the MP_Agent register */
+ 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 */
+
+ HalpCheckSpuriousInt();
+ return;
+ }
+
+ if (itpend & MPA_INTN_ITMSG2) {
+
+ //
+ // reading the message register clears the interrupt from the MP Agent
+ // we use message register 2 for the restart message
+ //
+
+ msg_data = (READ_REGISTER_ULONG(&(mpagent->datamsg2)) >> 24);
+ HalpCheckSpuriousInt();
+
+#if DBGG
+ DbgPrint("HAL: Warning: IPI Interrupt Message in Register 2\n");
+#endif
+
+ 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();
+
+#if DBGG
+ DbgPrint("HAL: Warning: IPI Interrupt Message in Register 3\n");
+#endif
+
+ 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(VOID)
+{
+
+ULONG itpend, causeit, pending;
+ULONG cpureg, tempreg;
+
+ 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 */
+
+ pending &= (
+ ((cpureg & (MPA_ENINT_SR_IP3 |
+ MPA_ENINT_SR_IP4 |
+ MPA_ENINT_SR_IP5 |
+ 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))
+ );
+ 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 DBG
+ ++PCR->HalReserved[0] ;
+#endif
+ return 1; /* Possible spurious ! */
+ }
+ }
+
+ return 0; /* No possible spurious ! */
+
+}
diff --git a/private/ntos/nthals/halsni4x/mips/mpagent.h b/private/ntos/nthals/halsni4x/mips/mpagent.h
new file mode 100644
index 000000000..bb3d3447a
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/mpagent.h
@@ -0,0 +1,535 @@
+//
+// 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_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 */
+
+
+/* +---------------------------+ */
+/* ! 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 100
+
+#endif
diff --git a/private/ntos/nthals/halsni4x/mips/orcache.s b/private/ntos/nthals/halsni4x/mips/orcache.s
new file mode 100644
index 000000000..5376f1f11
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/orcache.s
@@ -0,0 +1,628 @@
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halvlbms/src/hal/halsni4x/mips/RCS/orcache.s,v 1.1 1995/05/19 11:22:59 flo 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 0xb5000000
+//
+// 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("Orion Processor Identification")
+//++
+//
+// VOID
+// HalpOrionIdentify()
+//
+// Routine Description:
+//
+// This function reads the implementation number in the prid register if
+// a secondary cache exists : ORION without SC = R4x000.
+//
+// Arguments:
+//
+// None
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalpOrionIdentify)
+
+ .set noreorder
+ .set noat
+ lw v0,KiPcr + PcSecondLevelDcacheFillSize(zero) // get 2nd fill size
+ nop
+ beq v0,zero,10f
+ nop
+ mfc0 v0,prid
+ srl v0,PRID_IMP
+ and v0,0xff
+10: j ra
+
+ .end HalpOrionIdentify
+
+
+ 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
+ la t0, HalpLedAddress // get the address for the LED register
+ lw t0, 0(t0)
+ lw t1, KiPcr + PcSetMember(zero) // get a bitmapped value for Processor Number
+ or t1, t1, FLUSH_DCACHE_PAGE // what are we doing ?
+ xor t1, t1, 0xff // inverse
+ sb t1, 0(t0) // display it
+
+#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
+
+ la t0, HalpLedAddress // get the address for the LED register
+ lw t0, 0(t0)
+ lw t1, KiPcr + PcSetMember(zero) // get a bitmapped value for Processor Number
+ or t1, t1, PURGE_ICACHE_PAGE // what are we doing ?
+ xor t1, t1, 0xff // inverse
+ sb t1, 0(t0) // display it
+#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
+ la t0, HalpLedAddress // get the address for the LED register
+ lw t0, 0(t0)
+ lw t1, KiPcr + PcSetMember(zero) // get a bitmapped value for Processor Number
+ or t1, t1, SWEEP_DCACHE // what are we doing ?
+ xor t1, t1, 0xff // inverse
+ sb t1, 0(t0) // display it
+#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
+ la t0, HalpLedAddress // get the address for the LED register
+ lw t0, 0(t0)
+ lw t1, KiPcr + PcSetMember(zero) // get a bitmapped value for Processor Number
+ or t1, t1, SWEEP_ICACHE // what are we doing ?
+ xor t1, t1, 0xff // inverse
+ sb t1, 0(t0) // display it
+#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
+#if DBG
+ la t0, HalpLedAddress // get the address for the LED register
+ lw t0, 0(t0)
+ lw t1, KiPcr + PcSetMember(zero) // get a bitmapped value for Processor Number
+ or t1, t1, ZERO_PAGE // what are we doing ?
+ xor t1, t1, 0xff // inverse
+ sb t1, 0(t0) // display it
+#endif
+
+ 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/halsni4x/mips/r4intdsp.c b/private/ntos/nthals/halsni4x/mips/r4intdsp.c
new file mode 100644
index 000000000..855e2a4fd
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/r4intdsp.c
@@ -0,0 +1,1052 @@
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk351/src/hal/halsni4x/mips/RCS/r4intdsp.c,v 1.1 1995/05/19 11:23:26 flo 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"
+
+//
+// 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 HalpDismissTimeoutInterrupts();
+extern VOID HalpDisableTimeoutInterrupts();
+extern VOID HalpEnableTimeoutInterrupts();
+extern VOID HalpSendIpi(IN ULONG pcpumask, IN ULONG msg_data);
+
+#define TIMEOUT_MAX_COUNT 100
+
+KINTERRUPT HalpInt0Interrupt; // Interrupt Object for SC machines (centralised interrupt)
+KINTERRUPT HalpInt1Interrupt; // for SCSI/EISA interrupts (???)
+KINTERRUPT HalpInt3Interrupt; // Interrupt Object for IT3 tower multipro
+KINTERRUPT HalpInt4Interrupt; // Interrupt Object for IT4 tower multipro
+
+ULONG HalpTimeoutCount=0; // simple counter
+
+
+BOOLEAN
+HalpCreateIntStructures (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the structures necessary for Int0-handling
+ and connects the intermediate interrupt dispatcher.
+ Also the structures necessary for Int1 (EISA/SCSI)
+ (nicht noetig , Int4 (duart), Int6 (ethernet) and Int7 (BPINT) )
+ are initialized and connected.
+ The timer interrupt handler was directly written in the IDT (see
+ CLOCK2_LEVEL entries in r4initnt.c and r4calstl.c )
+ The last step in this routine is the call of
+ HalpCreateEisaStructures() - a function which initializes
+ the EISA interrupt controllers and
+ connects the central EISA ISR HalpEisaDispatch().
+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);
+
+ switch (HalpMainBoard) {
+ case M8036 : InterruptSourceRegister = (PVOID)RM200_INTERRUPT_SOURCE_REGISTER;
+ DispatchRoutine = HalpRM200Int0Dispatch;
+ break;
+ case M8032 : InterruptSourceRegister = (PVOID)RM400_TOWER_INTERRUPT_SOURCE_REGISTER;
+ DispatchRoutine = HalpRM400TowerInt0Dispatch;
+ break;
+ case M8042 :
+ default: InterruptSourceRegister = (PVOID)RM400_INTERRUPT_SOURCE_REGISTER;
+ DispatchRoutine = HalpRM400Int0Dispatch;
+ }
+
+ KeInitializeInterrupt( &HalpInt0Interrupt,
+ DispatchRoutine,
+ InterruptSourceRegister,
+ (PKSPIN_LOCK)NULL,
+ 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);
+ }
+
+ //
+ // this is the "fast" way to connect the interrupt
+ // PCR->InterruptRoutine[INT0_LEVEL] = HalpInt0Dispatch;
+
+
+ //
+ // Initialize the EISA/SCSI interrupt dispatcher for the Minitower.
+ //
+
+ KeInitializeInterrupt( &HalpInt1Interrupt,
+ HalpInt1Dispatch,
+ InterruptSourceRegister, // Interrupt Source Register
+ (PKSPIN_LOCK)NULL,
+ SCSIEISA_LEVEL, //INT1_INDEX,
+ SCSIEISA_LEVEL, //INT1_LEVEL,
+ SCSIEISA_LEVEL, //INT1_SYNC_LEVEL,
+ //Synchronize Irql ???
+ LevelSensitive,
+ TRUE,
+ 0, // processor number
+ FALSE // floating point registers
+ // and pipe line are not
+ // saved before calling
+ // the service routine
+ );
+
+ if (!KeConnectInterrupt( &HalpInt1Interrupt )) {
+
+ //
+ // this is the SCSI/EISA Interrupt for the SNI machines
+ //
+
+ HalDisplayString(" Failed to connect Int 1\n");
+ return(FALSE);
+ }
+
+ return (TRUE);
+}
+
+
+BOOLEAN
+HalpCreateIntMultiStructures (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the structures necessary for
+ dispatch interrupts management (not centralised ones).
+ Only used with mpagent.
+
+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.
+
+--*/
+
+{
+
+ KeInitializeInterrupt( &HalpInt3Interrupt,
+ HalpRM400Int3Process,
+ (PVOID)RM400_TOWER_INTERRUPT_SOURCE_REGISTER,
+ (PKSPIN_LOCK)NULL,
+ INT3_LEVEL,
+ INT3_LEVEL, //INT3_LEVEL,
+ INT3_LEVEL, //Synchr. Level
+ LevelSensitive,
+ FALSE,
+ 0, // processor number
+ FALSE // floating point registers
+ // and pipe line are not
+ // saved before calling
+ // the service routine
+ );
+
+ if (!KeConnectInterrupt( &HalpInt3Interrupt )) {
+
+ //
+ // this is the Interrupt for Debug, Timeout and EIP
+ //
+
+ HalDisplayString("Failed to connect Int3!\n");
+ return(FALSE);
+ }
+
+ KeInitializeInterrupt( &HalpInt4Interrupt,
+ HalpRM400Int4Process,
+ (PVOID)RM400_TOWER_INTERRUPT_SOURCE_REGISTER,
+ (PKSPIN_LOCK)NULL,
+ SCSIEISA_LEVEL,
+ SCSIEISA_LEVEL, // SCSIEISA_LEVEL,
+ SCSIEISA_LEVEL, // Synchr. Level
+ LevelSensitive,
+ FALSE,
+ 0, // processor number
+ FALSE // floating point registers
+ // and pipe line are not
+ // saved before calling
+ // the service routine
+ );
+
+ if (!KeConnectInterrupt( &HalpInt4Interrupt )) {
+
+ //
+ // this is the Interrupt for Debug, Timeout and EIP
+ //
+
+ HalDisplayString("Failed to connect Int4!\n");
+ return(FALSE);
+ }
+
+
+ return (TRUE);
+}
+
+BOOLEAN
+HalpRM200Int0Dispatch (
+ IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext
+ )
+/*++
+Routine Description:
+
+ This routine handles the central INT0 Interrupt on an SNI Desktop Model
+ To decide which interrupt, read the Interrupt Source Register
+
+
+ At the moment we test different interrupt handling
+ Handle all pending interrupts from highest level to the lowest or
+ Handle the highest Interrupt only
+
+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;
+ BOOLEAN SCSIresult, NETresult ;
+
+ IntSource = READ_REGISTER_UCHAR(ServiceContext);
+
+
+ IntSource ^= RM200_INTERRUPT_MASK; // XOR the low active bits with 1 gives 1
+ // ans XOR the high active with 0 gives 1
+
+ //
+ // on the Desktop Model, most interrupt will occcur on the onboard components
+ // so, give them the highest priority by serving them first, but FIRST check for timeout
+ // interrupts
+
+ // At the moment we have assigned the following priorities:
+ // Timeout Interrupt (a timeout may prevent other interrupt dispatch code to work correct)
+ // Onboard (System Clock on Isa Interrupt 0 every 10ms)
+ // SCSI Controller
+ // Network Controller
+ // Eisa Extension Board
+ // PushButton
+
+ if ( IntSource & RM200_TIMEOUT_MASK) { // TIMEOUT Interrupt
+
+ HalpDismissTimeoutInterrupts();
+
+ if (++HalpTimeoutCount >= TIMEOUT_MAX_COUNT) {
+
+ //
+ // if we get a lot of them, simply disable them ...
+ //
+
+ HalpDisableTimeoutInterrupts();
+
+ }
+ }
+
+ if ( IntSource & RM200_ONBOARD_MASK) { // ISA (onboard) Interrupt
+
+ return HalpEisaDispatch( NULL, // InterruptObject (unused)
+ (PVOID)RM200_ONBOARD_CONTROL_PHYSICAL_BASE // ServiceContext
+ );
+ }
+
+ //
+ // look for SCSI Interrupts
+ //
+
+ if ( IntSource & RM200_SCSI_MASK){
+ SCSIresult = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[SCSI_VECTOR])(
+ PCR->InterruptRoutine[SCSI_VECTOR]
+ );
+ return(SCSIresult);
+ }
+
+ //
+ // look for an Ethernet Interrupt
+ //
+
+ if ( IntSource & RM200_NET_MASK){
+ NETresult = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[NET_LEVEL])(
+ PCR->InterruptRoutine[NET_LEVEL]
+ );
+ return(NETresult);
+ }
+
+ //
+ // on an Desktop we may only have Eisa Interrupts when the
+ // Eisa backplane is installed
+ //
+
+ if ( IntSource & RM200_EISA_MASK) { // EISA Interrupt
+
+ if (HalpEisaExtensionInstalled) {
+ return HalpEisaDispatch( NULL, // InterruptObject (unused)
+ (PVOID)EISA_CONTROL_PHYSICAL_BASE // ServiceContext
+ );
+
+ } else {
+ DebugPrint(("HAL: Unexpected EISA interrupt with no EISA backplane installed !\n"));
+ }
+ }
+
+
+ //
+ // look for an PushButton Interrupt
+ // we may use this on a checked build for breaking into debugger
+ //
+
+ if ( IntSource & RM200_PB_MASK){
+
+ WRITE_REGISTER_UCHAR( RM200_RESET_DBG_BUT ,0x0); // reset debug intr
+#if DBG
+ DbgBreakPoint();
+#endif
+ KeStallExecutionProcessor(500000); // sleep 0.5 sec
+
+ }
+
+ return (TRUE); // perhaps on of the interrupts was pending :-)
+}
+
+
+BOOLEAN
+HalpRM400Int0Dispatch (
+ IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext
+ )
+/*++
+Routine Description:
+
+ This routine handles the central INT0 Interrupt on an SNI R4x00SC Minitower
+ To decide which interrupt, read the Interrupt Source Register
+
+ On an SC model and on the SNI Desktop, we havew to manage priorities by software,
+ because the HW priority over the Cause Bits has only 1 input - the Int0
+
+ At the moment we test different interrupt handling
+ Handle all pending interrupts from highest level to the lowest or
+ Handle the highest Interrupt only
+
+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;
+
+ BOOLEAN SCSIresult, NETresult;
+
+ IntSource = READ_REGISTER_UCHAR(ServiceContext);
+
+
+ IntSource ^= RM400_INTERRUPT_MASK; // XOR the low active bits with 1 gives 1
+ // ans XOR the high active with 0 gives 1
+ // so 0101 1111 gives 1 for EISA, SCSI, Timer0,
+ // Timer1, Net and Push Button
+
+
+ //
+ // on an RM400 we may have to look for OverTemperature and Timeout Interrupts
+ // and PushButton in the machineStatus register
+ //
+
+ MaStatus = READ_REGISTER_UCHAR(RM400_MSR_ADDR);
+
+ //
+ // I like High actice bits ....
+ //
+
+ MaStatus ^= RM400_MSR_MASK;
+
+ // these are the priorities on an Minitower
+ // Timeout Interrupt (a timeout may prevent other interrupt dispatch code to work correct)
+ // Eisa (onboard)Interrupts
+ // SCSI Controler
+ // Network
+ // NO extra Timer in local I/O space (not used on UniProcessor)
+ // PushButton
+ // Temperature
+ //
+
+ if ( MaStatus & RM400_MSR_TIMEOUT_MASK) { // TIMEOUT Interrupt
+
+ DebugPrint(("Interrupt - Timeout\n"));
+ HalpDismissTimeoutInterrupts();
+
+ if (++HalpTimeoutCount >= TIMEOUT_MAX_COUNT) {
+
+ //
+ // if we get a lot of them, simply disable them ...
+ //
+
+ HalpDisableTimeoutInterrupts();
+
+ }
+ }
+
+ if ( IntSource & RM400_EISA_MASK) { // EISA Interrupt
+
+ return HalpEisaDispatch( NULL, // InterruptObject (unused)
+ (PVOID)EISA_CONTROL_PHYSICAL_BASE // ServiceContext
+ );
+
+ }
+
+ //
+ // look for SCSI Interrupts
+ //
+
+ if ( IntSource & RM400_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
+ return(SCSIresult);
+
+ }
+
+
+ //
+ // look for an Ethernet Interrupt
+ //
+
+ if ( IntSource & RM400_NET_MASK){
+ NETresult = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[NET_LEVEL])(
+ PCR->InterruptRoutine[NET_LEVEL]
+ );
+ return(NETresult);
+ }
+
+ //
+ // look for an PushButton Interrupt and simply dismiss it
+ //
+
+ if ( MaStatus & RM400_MSR_PB_MASK){
+ DebugPrint(("Interrupt - PushButton\n"));
+ WRITE_REGISTER_UCHAR( RM400_RESET_DBG_BUT ,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 & RM400_MSR_TEMP_MASK){
+
+ DebugPrint(("Interrupt - Temperature\n"));
+
+ // Reset hardware detection
+
+ WRITE_REGISTER_UCHAR( RM400_MCR_ADDR ,MCR_TEMPBATACK | MCR_PODD);
+
+ // Enable new hardware detection
+
+ WRITE_REGISTER_UCHAR( RM400_MCR_ADDR , MCR_PODD);
+ WRITE_REGISTER_UCHAR( RM400_RESET_TEMPBAT_INTR ,0x0); // reset interrupt
+
+ // currently, no action
+ }
+
+ return (TRUE); // perhaps on of the interrupts was pending :-)
+}
+
+
+BOOLEAN
+HalpRM400TowerInt0Dispatch (
+ IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext
+ )
+/*++
+Routine Description:
+
+ This routine handles the central INT0 Interrupt on an SNI R4x00SC Tower
+ To decide which interrupt, read the Interrupt Source Register
+
+ On an Tower model, we have also to manage priorities by software,
+ because the HW priority over the Cause Bits has only 1 input - the Int0
+
+ At the moment we test different interrupt handling
+ Handle all pending interrupts from highest level to the lowest or
+ Handle the highest Interrupt only
+
+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;
+
+ BOOLEAN SCSIresult, NETresult;
+
+ IntSource = READ_REGISTER_UCHAR(ServiceContext);
+
+ IntSource ^= RM400_TOWER_INTERRUPT_MASK; // XOR the low active bits with 1 gives 1
+ // ans XOR the high active with 0 gives 1
+ // so 0101 1111 gives 1 for EISA, SCSI, Timer0,
+ // Timer1, Net and Push Button
+
+
+ //
+ // on an RM400 Tower we may have to look for EIP, Timeout Interrupts
+ // and PushButton in the machineStatus register
+ // OverTemperature, Fan Control, BBU etc is handled by the EIP Processor
+ //
+
+ MaStatus = READ_REGISTER_UCHAR(RM400_MSR_ADDR);
+
+ //
+ // I like High actice bits ....
+ //
+
+ MaStatus ^= RM400_MSR_MASK;
+
+ // these are the priorities on an RM400-TOwer
+ // Extra Clock (used only on MultiPro machines)
+ // Timeout Interrupts
+ // Eisa (onboard)Interrupts
+ // SCSI Controler
+ // Network
+ // extra Timer in local I/O space (this may be changed on an MULTI)
+ // PushButton
+ // EIP Peripherial Processor
+
+ if ( MaStatus & RM400_MSR_TIMEOUT_MASK) { // TIMEOUT Interrupt
+
+ DebugPrint(("Interrupt - Timeout\n"));
+ HalpDismissTimeoutInterrupts();
+
+ if (++HalpTimeoutCount >= TIMEOUT_MAX_COUNT) {
+
+ //
+ // if we get a lot of them, simply disable them ...
+ //
+
+ HalpDisableTimeoutInterrupts();
+
+ }
+
+ return TRUE;
+ }
+
+ if ( IntSource & RM400_TOWER_EISA_MASK) { // EISA(onboard) Interrupt
+
+ return HalpEisaDispatch( NULL, // InterruptObject (unused)
+ (PVOID)EISA_CONTROL_PHYSICAL_BASE // ServiceContext
+ );
+
+ }
+
+ //
+ // look for SCSI Interrupts
+ //
+
+ if ( IntSource & RM400_TOWER_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
+ return(SCSIresult);
+
+ }
+
+
+ //
+ // look for an Ethernet Interrupt
+ //
+
+ if ( IntSource & RM400_TOWER_NET_MASK){
+ NETresult = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[NET_LEVEL])(
+ PCR->InterruptRoutine[NET_LEVEL]
+ );
+ return(NETresult);
+ }
+
+ //
+ // look for an PushButton Interrupt and simply dismiss it
+ //
+
+ if ( MaStatus & RM400_MSR_PB_MASK){
+ DebugPrint(("Interrupt - PushButton\n"));
+ WRITE_REGISTER_UCHAR( RM400_RESET_DBG_BUT ,0x0); // reset debug intr
+#if DBG
+ DbgBreakPoint();
+#endif
+ KeStallExecutionProcessor(500000); // sleep 0.5 sec
+ }
+
+ //
+ // look for an EIP Interrupt and ????
+ //
+
+ if ( MaStatus & RM400_MSR_EIP_MASK){
+
+ //
+ // we dont't know exactly how to handle this and it is not
+ // part of the HAL Spec. So we have assigned an IRQL to this -
+ // the EIP Software will know this and handle it correct
+ //
+
+ DebugPrint(("Got EIP Interrupts\nTransfering control to EIP Handling Routine\n"));
+
+ ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[EIP_VECTOR])(
+ PCR->InterruptRoutine[EIP_VECTOR]
+ );
+ //
+ // currently, no other action
+ //
+
+ }
+
+ return TRUE; // perhaps on of the interrupts was pending :-)
+}
+
+
+BOOLEAN
+HalpInt1Dispatch (
+ IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext
+ )
+/*++
+Routine Description:
+
+ If we use an R4x00PC model as CPU, we have some more direct hardware interrupts
+ direct connected to the CPU. So we have to test for timeout etc. at this place.
+ Handles on an RM400Minitower the SCSI/EISA Interrupt for R4x00 PC
+ To decide which interrupt, read the Interrupt Source Register
+
+Arguments:
+
+ Interrupt - Supplies a pointer to the interrupt object.
+
+ ServiceContext - Supplies a pointer to the Interrupt
+ Source register.
+
+ None.
+
+Return Value:
+
+ A BOOLEAN value, TRUE if the interrupt is OK,
+ otherwise FALSE for unknown interrupts
+
+--*/
+
+{
+
+ UCHAR IntSource;
+ UCHAR MaStatus;
+ BOOLEAN SCSIresult;
+
+ IntSource = READ_REGISTER_UCHAR(ServiceContext);
+ IntSource ^= RM400_INTERRUPT_MASK; // XOR the low active bits with 1 gives 1
+ // ans XOR the high active with 0 gives 1
+ // so 0101 1111 gives 1 for EISA, SCSI, Timer0,
+ // Timer1, Net and Push Button
+
+
+ //
+ // on an RM400 MiniTower we may have to look for Timeout Interrupts, OverTemperature
+ // and PushButton in the machineStatus register
+ //
+
+ MaStatus = READ_REGISTER_UCHAR(RM400_MSR_ADDR);
+
+ //
+ // I like High actice bits ....
+ //
+
+ MaStatus ^= RM400_MSR_MASK;
+
+ if ( MaStatus & RM400_MSR_TIMEOUT_MASK) { // TIMEOUT Interrupt
+
+ DebugPrint(("Interrupt - Timeout\n"));
+ HalpDismissTimeoutInterrupts();
+
+ if (++HalpTimeoutCount >= TIMEOUT_MAX_COUNT) {
+
+ //
+ // if we get a lot of them, simply disable them ...
+ //
+
+ HalpDisableTimeoutInterrupts();
+
+ }
+ }
+
+
+ //
+ // this is a new Minitower mainboard, so we can look in the Interrupt
+ // Source register for Interrupts ...
+ //
+
+
+ if ( IntSource & RM400_SCSI_MASK){ // SCSI Interrupt
+ SCSIresult = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[SCSI_VECTOR])(
+ PCR->InterruptRoutine[SCSI_VECTOR]
+ );
+
+#if DBG
+ if(!SCSIresult) DebugPrint(("Got an invalid SCSI interrupt !\n"));
+#endif
+ }
+
+ if ( IntSource & RM400_EISA_MASK) { // EISA (onboard)Interrupt
+ return HalpEisaDispatch( NULL, // InterruptObject (unused)
+ (PVOID)EISA_CONTROL_PHYSICAL_BASE // ServiceContext
+ );
+ }
+
+ //
+ // look for an PushButton Interrupt and simply dismiss it
+ //
+//#ifdef XXX
+
+ if ( MaStatus & RM400_MSR_PB_MASK){
+ DebugPrint(("Interrupt - PushButton\n"));
+ WRITE_REGISTER_UCHAR( RM400_RESET_DBG_BUT ,0x0); // reset debug intr
+#if DBG
+ DbgBreakPoint();
+#endif
+ KeStallExecutionProcessor(500000); // sleep 0.5 sec
+ }
+
+//#endif
+
+ //
+ // look for an OverTemperature Interrupt and simply dismiss it
+ //
+
+ if ( MaStatus & RM400_MSR_TEMP_MASK){
+
+ DebugPrint(("Interrupt - Temperature\n"));
+
+ // Reset hardware detection
+
+ WRITE_REGISTER_UCHAR( RM400_MCR_ADDR ,MCR_TEMPBATACK | MCR_PODD);
+
+ // Enable new hardware detection
+
+ WRITE_REGISTER_UCHAR( RM400_MCR_ADDR , MCR_PODD);
+ WRITE_REGISTER_UCHAR( RM400_RESET_TEMPBAT_INTR ,0x0); // reset interrupt
+
+ // currently, no action
+ }
+
+
+ return TRUE; // perhaps on of the interrupts was pending :-)
+}
+
+
+
+BOOLEAN
+HalpRM400Int3Process (
+ IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext
+ )
+/*++
+Routine Description:
+
+ This routine handles the INT3 Interrupt on an SNI R4x00SC Tower :
+
+ - Timeout
+ - Debug button
+ - EIP
+
+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 MaStatus;
+
+ //
+ // on an RM400 Tower we may have to look for EIP, Timeout Interrupts
+ // and PushButton in the machineStatus register
+ // OverTemperature, Fan Control, BBU etc is handled by the EIP Processor
+ //
+
+ MaStatus = READ_REGISTER_UCHAR(RM400_MSR_ADDR);
+
+ MaStatus ^= RM400_MSR_MASK; // I like High actice bits ....
+
+ if ( MaStatus & RM400_MSR_TIMEOUT_MASK) { // TIMEOUT Interrupt
+
+ DebugPrint(("Interrupt - Timeout\n"));
+ HalpDismissTimeoutInterrupts();
+
+ if (++HalpTimeoutCount >= TIMEOUT_MAX_COUNT) {
+
+ //
+ // if we get a lot of them, simply disable them ...
+ //
+
+ HalpDisableTimeoutInterrupts();
+
+ }
+
+ return TRUE;
+ }
+ //
+ // look for an PushButton Interrupt and simply dismiss it
+ //
+
+ if ( MaStatus & RM400_MSR_PB_MASK){
+ DebugPrint(("Interrupt - PushButton\n"));
+ WRITE_REGISTER_UCHAR( RM400_RESET_DBG_BUT ,0x0); // reset debug intr
+#if DBG
+ DbgBreakPoint();
+#endif
+ KeStallExecutionProcessor(500000); // sleep 0.5 sec
+ }
+
+ //
+ // look for an EIP Interrupt and ????
+ //
+
+ if ( MaStatus & RM400_MSR_EIP_MASK){
+
+ //
+ // we dont't know exactly how to handle this and it is not
+ // part of the HAL Spec. So we have assigned an IRQL to this -
+ // the EIP Software will know this and handle it correct
+ //
+
+ DebugPrint(("Got EIP Interrupts\nTransfering control to EIP Handling Routine\n"));
+
+ ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[EIP_VECTOR])(
+ PCR->InterruptRoutine[EIP_VECTOR]
+ );
+ //
+ // currently, no other action
+ //
+
+ }
+
+ return TRUE; // perhaps on of the interrupts was pending :-)
+}
+
+
+
+BOOLEAN
+HalpRM400Int4Process (
+ IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext
+ )
+/*++
+Routine Description:
+
+ This routine handles the INT4 Interrupt on an SNI R4x00SC Tower :
+
+ - EISA
+ - SCSI
+
+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;
+
+ BOOLEAN Result;
+
+ Result = FALSE;
+ IntSource = READ_REGISTER_UCHAR(ServiceContext);
+
+ IntSource ^= RM400_TOWER_INTERRUPT_MASK; // XOR the low active bits with 1 gives 1
+ // ans XOR the high active with 0 gives 1
+ // so 0101 1111 gives 1 for EISA, SCSI, Timer0,
+ // Timer1, Net and Push Button
+
+ if ( IntSource & RM400_TOWER_EISA_MASK) { // EISA(onboard) Interrupt
+
+ Result = HalpEisaDispatch( NULL, // InterruptObject (unused)
+ (PVOID)EISA_CONTROL_PHYSICAL_BASE // ServiceContext
+ );
+
+ }
+
+ //
+ // look for SCSI Interrupts
+ //
+
+ if ( IntSource & RM400_TOWER_SCSI_MASK){
+ Result = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[SCSI_VECTOR])(
+ PCR->InterruptRoutine[SCSI_VECTOR]
+ );
+#if DBG
+ if(!Result) DebugPrint(("Got an invalid SCSI interrupt !\n"));
+#endif
+
+ }
+
+ HalpCheckSpuriousInt();
+ return(Result);
+
+}
+
+
+VOID
+HalpRM400Int5Process (
+ )
+/*++
+Routine Description:
+
+ This routine handles the INT5 Interrupt on an SNI R4x00SC Tower :
+
+ - NET
+
+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
+
+--*/
+
+{
+ BOOLEAN Result;
+
+ Result = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[NET_LEVEL])(
+ PCR->InterruptRoutine[NET_LEVEL]
+ );
+#if DBG
+ if(!Result) DebugPrint(("Got an invalid NET interrupt !\n"));
+#endif
+
+ HalpCheckSpuriousInt();
+
+}
diff --git a/private/ntos/nthals/halsni4x/mips/snidef.h b/private/ntos/nthals/halsni4x/mips/snidef.h
new file mode 100644
index 000000000..7eabd8dd8
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/snidef.h
@@ -0,0 +1,215 @@
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk35/src/hal/halsni/mips/RCS/snidef.h,v 1.6 1995/04/07 10:00:01 flo 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 "DESKdef.h"
+#include "MINIdef.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)
+#define MPAGENT_RESERVED 0x17c00000 // KSEG1 address of a 4M segment stolen
+ // in the upper part of the I/O EISA space
+ // to be used for cache replace operation.
+#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 0x160003f0 // base of floppy control
+#define PARALLEL_PHYSICAL_BASE 0x160003bc // base of parallel port
+#define SERIAL0_PHYSICAL_BASE 0x160003f8 // base of serial port 0
+#define SERIAL1_PHYSICAL_BASE 0x160002f8 // 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 3686400 // 3.6864 Mhz
+#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 EXTRA_CLOCK_LEVEL 6 // this is one of the extra timers on RM400
+#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 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 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
+
+
+#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/halsni4x/mips/snidisp.c b/private/ntos/nthals/halsni4x/mips/snidisp.c
new file mode 100644
index 000000000..343d20a6a
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/snidisp.c
@@ -0,0 +1,1475 @@
+#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk351/src/hal/halsni4x/mips/RCS/snidisp.c,v 1.3 1995/10/06 09:43:09 flo 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.
+ Because we have no full working Configuration management (yet), we try to
+ identitify some graphic boards ourself.
+
+ CHANGE CHANGE CHANGE now we have a working display configuration entry
+ Thanx to Mr. Pierre Sanguard, the firmware people from SNI France (Plaisir)
+
+ At the moment we know about the following boards:
+ P9000 based Cards: Orchid P9000 VLB / Diamond Viper
+ Standard S3 based ISA/VLB cards ( 80x50 Alpha Mode)
+ Standard Cirrus ISA/VLB cards ( 80x50 Alpha Mode)
+ Standard (unknown) VGA on ISA/VLB( 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.
+//
+
+BOOLEAN ICD2061LoadClockgen (PUCHAR port, ULONG data, LONG bitpos);
+BOOLEAN Bt485InitRamdac (VOID);
+LONG ICD2061CalcClockgen (LONG freq);
+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 HalpResetP9100 (VOID);
+VOID HalpVGASetup (VOID);
+VOID HalpDoNoSetup (VOID);
+
+
+typedef
+VOID
+(*PHALP_CONTROLLER_SETUP) (
+ VOID
+ );
+
+
+//
+// Supported board definitions.
+//
+
+typedef enum _VIDEO_BOARD {
+ P9000_RM400 = 0, // SNI specific Video Board for the RM400-10
+ P9000_ORCHID, // Orchid P9000 VLB (Vesa Local Bus)
+ P9000_VIPER, // Diamond Viper (Vesa Local Bus P9000)
+ 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
+ P9100_WEITEK, // Diamond (Vesa Local Bus P9100)
+ VIDEO_BOARD_UNKNOWN // unknown Display Adapter
+} VIDEO_BOARD;
+
+//
+// some supported VGA chips
+//
+
+typedef enum _VIDEO_CHIP {
+ P9000 = 0,
+ S3,
+ CIRRUS,
+ VGA, // generic (unknown) VGA
+ VGA_P9000,
+ VGA_P9100,
+ 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[] = {
+ {"ORCHID P9000 VLBUS", HalpVGASetup , P9000_ORCHID , VGA_P9000 },
+ {"DIAMOND P9000 VLBUS", HalpVGASetup , P9000_VIPER , VGA_P9000 },
+ {"VGA ON ATBUS", HalpVGASetup , VGA_GENERIC , VGA },
+ {"S3 BASED VLBUS", HalpVGASetup , S3_GENERIC_VLB, S3 },
+ {"CIRRUS BASED VLBUS", HalpVGASetup , CIRRUS_GENERIC_VLB, CIRRUS},
+ {"CIRRUS ON BOARD", HalpVGASetup , CIRRUS_ONBOARD, CIRRUS},
+ {"CIRRUS ONBOARD", HalpVGASetup , CIRRUS_ONBOARD, CIRRUS},
+ {"VGA ON VLBUS", HalpVGASetup , VGA_GENERIC_VLB, VGA },
+ {"DIAMOND P9100 VLBUS", HalpVGASetup , P9100_WEITEK , VGA_P9100 }
+};
+
+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;
+
+//
+// Declare externally defined data.
+//
+
+
+BOOLEAN HalpDisplayOwnedByHal;
+
+//
+// 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 = HalpDoNoSetup;
+
+ //
+ // 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;
+ 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;
+
+
+ switch (HalpVideoBoard){
+ case S3_GENERIC_VLB:
+ case CIRRUS_GENERIC_VLB:
+ case VGA_GENERIC_VLB:
+ case P9100_WEITEK:
+//
+// N.B.
+// on an SNI desktop model the VL I/O space is transparent, so
+// acces in the normal Backplane area results in correct values
+// the minitower instead, does not decode all VL signals correct,
+// so ther is an EXTRA I/O space for accessing VL I/O (0x1exxxxxx)
+// this is handled in the definition of VESA_IO in SNIdef.h
+//
+
+ HalpVGAControlBase = (HalpIsRM200) ? (PVOID)HalpEisaControlBase : (PVOID)VESA_IO;
+ VideoBuffer = ( PUSHORT)( VESA_BUS + 0xb8000);
+ FontBuffer = ( PUCHAR )( VESA_BUS + 0xa0000);
+
+ break;
+
+ case CIRRUS_ONBOARD:
+ HalpVGAControlBase = (PVOID)HalpOnboardControlBase;
+ VideoBuffer = ( PUSHORT)( RM200_ONBOARD_MEMORY + 0xb8000);
+ FontBuffer = ( PUCHAR )( RM200_ONBOARD_MEMORY + 0xa0000);
+ break;
+
+ case S3_GENERIC:
+ case CIRRUS_GENERIC:
+ case VGA_GENERIC:
+ default:
+ HalpVGAControlBase = (PVOID)HalpEisaControlBase;
+ VideoBuffer = ( PUSHORT)( EISA_MEMORY_BASE + 0xb8000);
+ FontBuffer = ( PUCHAR )( EISA_MEMORY_BASE + 0xa0000);
+ break;
+ }
+
+
+
+ //
+ // 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 VGA_P9000:
+ HalpResetP9000();
+
+ //
+ // we have programmed the clock into register 0 of the ICD2061, so
+ // select it via the VGA_MISC register
+ //
+
+// WRITE_REGISTER_UCHAR(VGA_MISC_WRITE, 0xa3);
+ break;
+
+ case S3: HalpResetS3Chip();
+ break;
+
+ case CIRRUS: HalpResetCirrusChip();
+ break;
+
+ case VGA_P9100:
+ HalpResetP9100();
+ 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) {
+
+ 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;
+
+ // 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 (TextMode == TEXT_132x50) {
+ // external clock (40MHz)
+ WRITE_REGISTER_UCHAR(VGA_MISC_WRITE, 0xAF);
+ } else {
+ // COLOR registers , enable RAM, 25 MHz (???) 400 Lines,
+ if (HalpVideoChip == VGA_P9100) {
+ WRITE_REGISTER_UCHAR(VGA_MISC_WRITE, 0x67) ; // 28.322 Mhz
+ } else {
+ WRITE_REGISTER_UCHAR(VGA_MISC_WRITE, 0x63) ; // 25,175 MHz (don't use with P9100).
+ }
+ }
+
+ // 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
+HalpResetP9100(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the VGA part of an Orchid P9000VLB or Diamond Viper card
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ LONG IcdVal;
+ int i;
+
+ //
+ // First, reprogram register broken by the p9100 driver
+ //
+
+ switch (HalpMainBoard) {
+ case M8036:
+ WRITE_REGISTER_UCHAR (0xbfcc0000, 0x00); // RM200
+ break;
+ case M8042 :
+ WRITE_REGISTER_UCHAR (0xbc010000, 0xff); // RM400 MT
+ break;
+ case M8032 :
+ WRITE_REGISTER_UCHAR (0xbc0c0000, 0xff); // RM400 T
+ break;
+ }
+
+ //
+ // unlock and disable the P9000 on the board
+ //
+
+ WRITE_REGISTER_UCHAR (VGA_SEQ_IDX, 0x11);
+ WRITE_REGISTER_UCHAR (VGA_SEQ_DATA,0x00); // unlock extended SEQ reg
+ WRITE_REGISTER_UCHAR (VGA_SEQ_DATA,0x00);
+ WRITE_REGISTER_UCHAR (VGA_SEQ_DATA,0x00);
+ WRITE_REGISTER_UCHAR (VGA_SEQ_IDX, 0x12); // select extended reg 0x12
+
+ if (HalpVideoBoard == P9000_ORCHID) {
+ WRITE_REGISTER_UCHAR (VGA_SEQ_DATA, 0x08);
+ } else {
+ WRITE_REGISTER_UCHAR (VGA_SEQ_DATA, 0x88);
+ }
+
+ //
+ // init the clock generator, we use use the 80x50 Text mode
+ // so we need a 25.175Mhz clock
+ //
+
+// if(( IcdVal = ICD2061CalcClockgen(25175)) == -1){
+// DebugPrint(("HAL: Error calculating ICD Value for 25.175Mhz\n"));
+// }
+
+// byte = READ_REGISTER_UCHAR((PUCHAR) VGA_MISC_WRITE);
+ IcdVal = 0x7170a0;ICD2061LoadClockgen((PUCHAR) VGA_MISC_WRITE , IcdVal, 2);
+ IcdVal = 0x01a8bc;ICD2061LoadClockgen((PUCHAR) VGA_MISC_WRITE , IcdVal, 2);
+ IcdVal = 0x2560ac;ICD2061LoadClockgen((PUCHAR) VGA_MISC_WRITE , IcdVal, 2);
+ IcdVal = 0x4560ac;ICD2061LoadClockgen((PUCHAR) VGA_MISC_WRITE , IcdVal, 2);
+// WRITE_REGISTER_UCHAR((PUCHAR) VGA_MISC_WRITE,byte);
+ WRITE_REGISTER_UCHAR(VGA_MISC_WRITE, 0x67) ; // 28.322 Mhz - crt ad = 3dx
+
+ //
+ // if this is the first initialisation i.e. Systemboot,
+ // the firmware has initialized the VGA part properly
+ //
+
+ if (HalpFirstBoot) return;
+
+ WRITE_REGISTER_UCHAR( P9100_CFG_IDX, P9100_CONFIG_REG); // enable VGA
+ WRITE_REGISTER_UCHAR( P9100_CFG_DATA, 0x02);
+
+ WRITE_REGISTER_UCHAR( P9100_CFG_IDX, P9100_COMMAND_REG); // enable I/O space - ctl VGA palette snoop
+ WRITE_REGISTER_UCHAR( P9100_CFG_DATA, 0x83);
+
+ WRITE_REGISTER_UCHAR( P9100_CFG_IDX, P9100_MEM_BASE_ADDR_REG); // why not...
+ WRITE_REGISTER_UCHAR( P9100_CFG_DATA, 0x00);
+
+ // init ramdac (bug workaround + other unknown things...)
+ WRITE_REGISTER_UCHAR( P9100_CFG_IDX, P9100_CONFIG_REG); // enable VGA
+ WRITE_REGISTER_UCHAR( P9100_CFG_DATA, 0x00);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_HIGH_ADDR, 0x00000000);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_LOW_ADDR, 0x90909090);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_CTRL, 0x01010101);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_DATA, 0x03030303);
+
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_HIGH_ADDR, 0x00000000);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_LOW_ADDR, 0x70707070);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_CTRL, 0x01010101);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_DATA, 0x40404040);
+
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_HIGH_ADDR, 0x00000000);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_LOW_ADDR, 0x0a0a0a0a);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_CTRL, 0x02020202);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_DATA, 0x40404040);
+
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_HIGH_ADDR, 0x00000000);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_LOW_ADDR, 0x71717171);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_CTRL, 0x01010101);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_DATA, 0x40404040);
+
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_HIGH_ADDR, 0x00000000);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_LOW_ADDR, 0x71717171);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_CTRL, 0x01010101);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_DATA, 0x00000000);
+
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_HIGH_ADDR, 0x00000000);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_LOW_ADDR, 0x02020202);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_CTRL, 0x01010101);
+ for(i=2;i <= 0x72; ++i) {
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_DATA, 0x00000000);
+ }
+
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_HIGH_ADDR, 0x00000000);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_CTRL, 0x00000000);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_LOW_ADDR, 0x02020202);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_DATA, 0x01010101);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_LOW_ADDR, 0x0a0a0a0a);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_DATA, 0x03030303);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_LOW_ADDR, 0x14141414);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_DATA, 0x0e0e0e0e);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_LOW_ADDR, 0x20202020);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_DATA, 0x24242424);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_LOW_ADDR, 0x21212121);
+ WRITE_REGISTER_ULONG( P9100_RAMDAC_DATA, 0x30303030);
+
+ WRITE_REGISTER_UCHAR( P9100_CFG_IDX, P9100_CONFIG_REG); // enable VGA
+ WRITE_REGISTER_UCHAR( P9100_CFG_DATA, 0x02);
+
+ WRITE_REGISTER_UCHAR(VGA_MISC_WRITE, 0x67) ; // 28.322 Mhz - crt ad = 3dx
+
+}
+
+VOID
+HalpResetP9000(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the VGA part of an Orchid P9000VLB or Diamond Viper card
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ LONG IcdVal;
+
+ //
+ // unlock and disable the P9000 on the board
+ //
+
+ WRITE_REGISTER_UCHAR (VGA_SEQ_IDX, 0x11);
+ WRITE_REGISTER_UCHAR (VGA_SEQ_DATA,0x00); // unlock extended SEQ reg
+ WRITE_REGISTER_UCHAR (VGA_SEQ_DATA,0x00);
+ WRITE_REGISTER_UCHAR (VGA_SEQ_DATA,0x00);
+ WRITE_REGISTER_UCHAR (VGA_SEQ_IDX, 0x12); // select extended reg 0x12
+
+ if (HalpVideoBoard == P9000_ORCHID) {
+ WRITE_REGISTER_UCHAR (VGA_SEQ_DATA, 0x08);
+ } else {
+ WRITE_REGISTER_UCHAR (VGA_SEQ_DATA, 0x88);
+ }
+
+
+ //
+ // init the clock generator, we use use the 80x50 Text mode
+ // so we need a 25.175Mhz clock
+ //
+
+ if(( IcdVal = ICD2061CalcClockgen(25175)) == -1){
+ DebugPrint(("HAL: Error calculating ICD Value for 25.175Mhz\n"));
+ }
+
+ ICD2061LoadClockgen((PUCHAR) VGA_MISC_WRITE , IcdVal, 2);
+
+ //
+ // if this is the first initialisation i.e. Systemboot,
+ // the firmware has initialized the VGA part properly
+ //
+
+ if (HalpFirstBoot) return;
+
+ //
+ // reset the RamDac (Bt485) to VGA mode, no clock doubler
+ //
+
+ WRITE_REGISTER_UCHAR( Bt485_CR0, 0xa0); // 6 bit operations, no sync on colors
+ WRITE_REGISTER_UCHAR( Bt485_CR1, 0x00); //
+// WRITE_REGISTER_UCHAR( Bt485_CR1, 0x40); //
+ WRITE_REGISTER_UCHAR( Bt485_CR2, 0x00); // select VGA port
+
+ // enable CR3 via CR0
+
+ WRITE_REGISTER_UCHAR( Bt485_ADDR, 0x01);
+ WRITE_REGISTER_UCHAR( Bt485_CR3, 0x00); // disable clock multiplier
+ WRITE_REGISTER_UCHAR( Bt485_MASK, 0xff);
+
+}
+
+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);
+
+}
+
+BOOLEAN
+ICD2061LoadClockgen(
+ PUCHAR port,
+ ULONG data,
+ LONG bitpos
+ )
+/*++
+
+Routine Description:
+
+ The ICD2061LoadClockgen() routine.
+ This routine loads the ICD206x Clock Generator with the given data
+ The circuit is programmed serial over 2 data Lines lines; clock and data
+ On an Plaisir Graphics board clock bit is bit 0
+ data bit is bit 1
+ On most VGA with an ICD2061 the lines are connected over the VGA_MISC Register
+ clock bit is bit 2
+ data bit is bit 3
+
+Arguments:
+
+ Arguments: the port for programming
+ the value
+ the BitPosition of the output port for clock and data line
+
+Return Value:
+
+ TRUE on success
+
+--*/
+{
+#define w_icd(x) WRITE_REGISTER_UCHAR(port, mask & (x))
+
+ ULONG tmp;
+ LONG i;
+ UCHAR mask = 0x3; // 00000011
+ UCHAR ck0 = 0x0; // Clock Bit = low
+ UCHAR ck1 = 0x1; // Clock Bit = high
+ UCHAR dat0 = 0x0; // Data Bit = low
+ UCHAR dat1 = 0x2; // Data Bit = high
+ ULONG shift = bitpos + 1; // Data bit
+
+ mask = mask << bitpos;
+ ck1 = ck1 << bitpos;
+ dat1 = dat1 << bitpos;
+
+ tmp = 0;
+ for (i=0; i<5; i++) {
+ w_icd(ck0 | dat1); // unlock bit 1-5
+ w_icd(ck1 | dat1);
+ }
+ w_icd(ck0 | dat0); // end of unlock sequence
+ w_icd(ck1 | dat0);
+ w_icd(ck0 | dat0); // start bit falling
+ w_icd(ck1 | dat0); // start bit rising
+
+ for (i=0; i<24; i++) { // write the 24 bits of data
+ w_icd(ck1 | (UCHAR)(((~data)&1)<<shift));
+ w_icd(ck0 | (UCHAR)(((~data)&1)<<shift));
+ w_icd(ck0 | (UCHAR)((data&1)<<shift));
+ w_icd(ck1 | (UCHAR)((data&1)<<shift));
+ data >>= 1;
+ }
+
+ w_icd(ck1 | dat1);
+ w_icd(ck0 | dat1); // stop bit
+ w_icd(ck1 | dat1); // stop bit
+ w_icd(0); // select REG0 video frequency
+
+
+ return (TRUE);
+}
+#undef w_icd
+
+LONG
+ICD2061CalcClockgen(
+ LONG freq
+ )
+/*++
+
+Routine Description:
+
+ The ICD2061CalcClockgen() routine.
+ This routine calculates the data for the ICD2062/ ICD2061 Clock Generator from the
+ given pixel frequency (in kHz).
+ The frequency in is kHz rather than MHz because the kernel does not support
+ floating point, and this routine had to be converted to integer.
+
+Arguments:
+
+ requested frequency.
+
+Return Value:
+
+ (-1), on error
+ the calculated data word, otherwise
+
+--*/
+{
+ int p, q, qlow, qhigh, bestp, bestq, mux, index;
+ int diff, bestdiff;
+ int fref = 14318;
+ int fvco, fcalc, qoverp;
+
+// check that frequency is derivable
+ if (freq < 625) return (-1);
+ else if (freq < 1250) mux = 6;
+ else if (freq < 2500) mux = 5;
+ else if (freq < 5000) mux = 4;
+ else if (freq < 10000) mux = 3;
+ else if (freq < 20000) mux = 2;
+ else if (freq < 40000) mux = 1;
+ else if (freq < 160000) mux = 0;
+ else return (-1);
+
+// calculate the index field
+ fvco = (1 << mux) * freq;
+
+ if (fvco < 40000) index = 0;
+ else if (fvco < 47500) index = 1;
+ else if (fvco < 52200) index = 2;
+ else if (fvco < 56300) index = 3;
+ else if (fvco < 61900) index = 4;
+ else if (fvco < 65000) index = 5;
+ else if (fvco < 68100) index = 6;
+ else if (fvco < 82300) index = 7;
+ else if (fvco < 86000) index = 8;
+ else if (fvco < 88000) index = 9;
+ else if (fvco < 90500) index = 10;
+ else if (fvco < 95000) index = 11;
+ else if (fvco < 100000) index = 12;
+ else index = 13;
+
+ qoverp = 1000 * 2 * fref / fvco;
+ qlow = (fref + 500)/1000;
+ qhigh = (fref * 5 - 500)/1000;
+ bestp = bestq = 0;
+ bestdiff = 10000;
+
+ for (p = 130; p >= 4; p--) {
+ q = (int)((qoverp * p + 500)/1000);
+ if ((q < qlow) || (q > qhigh)) continue;
+ fcalc = 2 * fref * p / q;
+ if (fcalc > fvco) diff = fcalc - fvco;
+ else diff = fvco - fcalc;
+ if (diff < bestdiff) {
+ bestdiff = diff;
+ bestp = p;
+ bestq = q;
+ }
+ }
+
+ if ((bestp == 0) || (bestq == 0)) return (-1);
+
+ return ( (index << 17) |
+ ((~(130 - bestp) & 0x7f) << 10) |
+ (mux << 7) |
+ (~(129 - bestq) & 0x7f) );
+}
+
+
diff --git a/private/ntos/nthals/halsni4x/mips/snihalp.h b/private/ntos/nthals/halsni4x/mips/snihalp.h
new file mode 100644
index 000000000..1967a0b91
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/snihalp.h
@@ -0,0 +1,338 @@
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk351/src/hal/halsni4x/mips/RCS/snihalp.h,v 1.1 1995/05/19 11:24:26 flo 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 BOOLEAN HalpEisaExtensionInstalled;
+extern BOOLEAN HalpIsRM200;
+extern BOOLEAN HalpIsMulti;
+
+extern KAFFINITY HalpActiveProcessors;
+
+//
+// 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
+
+//
+// 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
+ M8036 = 7 // RM200 Desktop
+} 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;
+extern ULONG HalpBusType;
+
+//
+// Firmware interface
+//
+
+typedef struct {
+ CHAR (*getchar)();
+ PCHAR (*gets)();
+ VOID (*printf)();
+ PCHAR (*parsefile)();
+ VOID (*reinit_slave)();
+} SNI_PRIVATE_VECTOR;
+
+//
+// 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
+ );
+
+BOOLEAN
+HalpCreateIntStructures(
+ VOID
+ );
+
+BOOLEAN
+HalpCreateIntMultiStructures (
+ VOID
+ );
+
+BOOLEAN
+HalpCreateEisaStructures(
+ IN INTERFACE_TYPE Interface
+ );
+
+
+VOID
+HalpDisableEisaInterrupt(
+ IN ULONG Vector
+ );
+
+VOID
+HalpEnableEisaInterrupt(
+ IN ULONG Vector,
+ IN KINTERRUPT_MODE InterruptMode
+ );
+
+VOID
+HalpDisableOnboardInterrupt(
+ IN ULONG Vector
+ );
+
+VOID
+HalpEnableOnboardInterrupt(
+ IN ULONG Vector,
+ IN KINTERRUPT_MODE InterruptMode
+ );
+
+BOOLEAN
+HalpEisaDispatch(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext
+ );
+
+
+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
+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
+ );
+
+VOID
+HalpRM400Int5Process (
+ );
+
+VOID
+HalpSystemInit(
+ VOID
+ );
+
+VOID
+HalpDisplayCopyRight(
+ VOID
+ );
+
+VOID
+HalpIpiInterrupt(
+ VOID
+ );
+
+VOID
+HalpInitMPAgent(
+ ULONG Number
+ );
+
+ULONG
+HalpOrionIdentify(
+ VOID
+ );
+
+BOOLEAN
+HalpMpAgentIdentify(
+ VOID
+ );
+
+#endif // _SNIHALP_
diff --git a/private/ntos/nthals/halsni4x/mips/sniregs.h b/private/ntos/nthals/halsni4x/mips/sniregs.h
new file mode 100644
index 000000000..83456a9b9
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/sniregs.h
@@ -0,0 +1,139 @@
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk35/src/hal/halsni/mips/RCS/sniregs.h,v 1.1 1994/10/13 15:47:06 holli 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/halsni4x/mips/unicache.s b/private/ntos/nthals/halsni4x/mips/unicache.s
new file mode 100644
index 000000000..d91a0f13a
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/unicache.s
@@ -0,0 +1,1098 @@
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halvlbms/src/hal/halsni4x/mips/RCS/unicache.s,v 1.1 1995/05/19 11:26:20 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
+
+ la t0, HalpLedAddress // get the address for the LED register
+ lw t0, 0(t0)
+ lw t1, KiPcr + PcSetMember(zero) // get a bitmapped value for Processor Number
+ or t1, t1, FLUSH_DCACHE_PAGE // what are we doing ?
+ xor t1, t1, 0xff // inverse
+ sb t1, 0(t0) // display it
+#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
+
+ la t0, HalpLedAddress // get the address for the LED register
+ lw t0, 0(t0)
+ lw t1, KiPcr + PcSetMember(zero) // get a bitmapped value for Processor Number
+ or t1, t1, PURGE_DCACHE_PAGE // what are we doing ?
+ xor t1, t1, 0xff // inverse
+ sb t1, 0(t0) // display it
+#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
+
+ la t0, HalpLedAddress // get the address for the LED register
+ lw t0, 0(t0)
+ lw t1, KiPcr + PcSetMember(zero) // get a bitmapped value for Processor Number
+ or t1, t1, PURGE_ICACHE_PAGE // what are we doing ?
+ xor t1, t1, 0xff // inverse
+ sb t1, 0(t0) // display it
+#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
+
+ la t0, HalpLedAddress // get the address for the LED register
+ lw t0, 0(t0)
+ lw t1, KiPcr + PcSetMember(zero) // get a bitmapped value for Processor Number
+ or t1, t1, SWEEP_DCACHE // what are we doing ?
+ xor t1, t1, 0xff // inverse
+ sb t1, 0(t0) // display it
+#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
+
+ la t0, HalpLedAddress // get the address for the LED register
+ lw t0, 0(t0)
+ lw t1, KiPcr + PcSetMember(zero) // get a bitmapped value for Processor Number
+ or t1, t1, SWEEP_ICACHE // what are we doing ?
+ xor t1, t1, 0xff // inverse
+ sb t1, 0(t0) // display it
+#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
diff --git a/private/ntos/nthals/halsni4x/mips/vgadata.h b/private/ntos/nthals/halsni4x/mips/vgadata.h
new file mode 100644
index 000000000..a98ee7e65
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/vgadata.h
@@ -0,0 +1,406 @@
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk35/src/hal/halsni/mips/RCS/vgadata.h,v 1.1 1994/10/13 15:47:06 holli Exp flo $")
+
+#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 P9100_CFG_IDX ((PVOID) ((ULONG)HalpVGAControlBase + 0x9100))
+#define P9100_CFG_DATA ((PVOID) ((ULONG)HalpVGAControlBase + 0x9104))
+#define P9100_CONFIG_REG 0x41
+#define P9100_COMMAND_REG 0x04
+#define P9100_MEM_BASE_ADDR_REG 0x13
+#define P9100_RAMDAC ((PVOID) ((ULONG)VESA_BUS + 0x60210))
+#define P9100_RAMDAC_LOW_ADDR ((PVOID) ((ULONG)VESA_BUS + 0x60210))
+#define P9100_RAMDAC_HIGH_ADDR ((PVOID) ((ULONG)VESA_BUS + 0x60214))
+#define P9100_RAMDAC_DATA ((PVOID) ((ULONG)VESA_BUS + 0x60218))
+#define P9100_RAMDAC_CTRL ((PVOID) ((ULONG)VESA_BUS + 0x6021c))
+
diff --git a/private/ntos/nthals/halsni4x/mips/x4clock.s b/private/ntos/nthals/halsni4x/mips/x4clock.s
new file mode 100644
index 000000000..44a813ebd
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/x4clock.s
@@ -0,0 +1,325 @@
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk35/src/hal/halsni/mips/RCS/x4clock.s,v 1.4 1995/02/13 12:54:07 flo 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"
+
+
+ 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 //
+
+#if DBG
+#else
+
+//
+// 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
+ la t0, HalpLedAddress // get address of the variable
+ lw t0,0(t0) // get value
+ sb a0,0(t0) // display LSByte (set the LED)
+#endif
+
+//
+// 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
+//
+
+ 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
+//15: beq zero,t0,20f // if eq, debugger not enabled
+ jal KdPollBreakIn // check if breakin is requested
+ beq zero,v0,40f // if eq, no breakin requested
+// beq zero,v0,20f // if eq, no breakin requested
+ li a0,DBG_STATUS_CONTROL_C // break in and send
+ jal DbgBreakPointWithStatus // status to debugger
+
+//
+// Check if profiling is active and the profile interval has expired.
+//
+//
+//20: la t0,HalpCountCompareInterrupt // profiling via CountCompare ?
+// lb t1,0(t0)
+// bne zero,t1,40f // if set, profiling is done via CountCompare Interrupt
+// lw t0,KiPcr + PcProfileCount(zero) // get remaining profile count
+// li t1,TIME_INCREMENT // get time increment value
+// beq zero,t0,40f // if eq, profiling not enabled
+// subu t0,t0,t1 // subtract time increment from count
+// bgtz t0,30f // if gtz, not end of profile interval
+// move a0,s8 // set address of trap frame
+// jal KeProfileInterrupt // process profile entries
+// lw t0,KiPcr + PcProfileInterval(zero) // get profile interval value
+//30: sw t0,KiPcr + PcProfileCount(zero) // set remaining profile count
+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 t0, RM400_TIMER0_ACK_ADDR // get address of acknowledge register
+ sb zero,0(t0) // acknowledge timer interrupt
+ jal HalpCheckSpuriousInt
+ 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("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
+
+ .set noreorder
+ .set noat
+
+ jal HalpCheckSpuriousInt
+ nop
+ 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
+ move a0,s8 // set address of trap frame
+ lw t4,__imp_KeProfileInterrupt // process profile interrupt
+ lw ra,CiRa(sp) // restore return address
+ addu sp,sp,CiFrameLength // deallocate stack frame
+ j t4 //
+
+ .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
diff --git a/private/ntos/nthals/halsni4x/mips/x4misc.s b/private/ntos/nthals/halsni4x/mips/x4misc.s
new file mode 100644
index 000000000..3a2515a7d
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/x4misc.s
@@ -0,0 +1,472 @@
+#if defined(R4000)
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk35/src/hal/halsni/mips/RCS/x4misc.s,v 1.4 1995/02/13 12:54:22 flo 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 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
+
+ SBTTL("Dismiss (acknowledge) Timeout Interrupts")
+//++
+//
+// ULONG
+// HalpDismissTimeoutInterrupts(
+// VOID
+// )
+//
+// Routine Description:
+//
+// This function it is called as an result of an (single) Timeout Interrupt
+// we reset the Bit 21 of the IOMemconf Register (disable Timeout) wait
+// and than we reenable Timeout Interrupts by setting Bit 21
+//
+// Note: Because the SNI ASIC is located at a special Address,
+// ( I have to study the docs again ...)
+// We have to set the Disable Parity Error and ECC Detection Bit in the
+// R4x00 Status register
+//
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// The value of the Status register.
+//
+//--
+
+ LEAF_ENTRY(HalpDismissTimeoutInterrupts)
+
+ .set noreorder
+ mfc0 v0,psr // get current PSR
+ nop // fill
+ nop
+ nop
+ or v1, v0, STATUS_DE // disable Parity/ Cache errors
+ and v1, v1, ~(STATUS_IE) // disable Interrupts
+ mtc0 v1, psr
+ nop
+ nop
+ nop
+ li t0, IOMEMCONF_ADDR // Timeout (and other) register
+ lw a0, 0(t0) // get the current value
+ and a1, a0, 0xffdfffff // reset bit 21
+ sw a1, 0(t0) // set IOMemconf Register
+ sync // flush write buffers
+
+//
+// execute a small time loop
+//
+
+ li a1,0x10
+1: nop
+ bne a1,zero,1b
+ subu a1,1 // BDSLOT
+
+ sw a0,0(t0) // restore old IOMemconf Register value
+ sync // flush write buffers
+
+ mtc0 v0, psr // restore old R4000 Status Register
+ nop
+ nop
+ nop
+ nop
+
+ .set reorder
+
+ j ra // return
+
+ .end HalpDismissTimeoutInterrupts
+
+ SBTTL("Disable Timeout Interrupts")
+//++
+//
+// ULONG
+// HalpDisableTimeoutInterrupts(
+// VOID
+// )
+//
+// Routine Description:
+//
+// This function it is called as an result of LOTS of LOTS of Timeout Interrupts,
+// so we disable them in the IOMemconfRegister (bit 21)
+// this is a stripped down version of HalpDismissTimeoutInterrupts()
+//
+// Note: Because the SNI ASIC is located at a special Address,
+// ( I have to study the docs again ...)
+// We have to set the Disable Parity Error and ECC Detection Bit in the
+// R4x00 Status register
+//
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// The value of the Status register.
+//
+//--
+
+ LEAF_ENTRY(HalpDisableTimeoutInterrupts)
+
+ .set noreorder
+ mfc0 v0,psr // get current PSR
+ nop // fill
+ nop
+ nop
+ or v1, v0, STATUS_DE // disable Parity/ Cache errors
+ and v1, v1, ~(STATUS_IE) // disable Interrupts
+ mtc0 v1, psr
+ nop
+ nop
+ nop
+ li t0, IOMEMCONF_ADDR // Timeout (and other) register
+ lw a0, 0(t0) // get the current value
+ and a1, a0, 0xffdfffff // reset bit 21
+ sw a1, 0(t0) // set register
+ sync // flush write buffers
+
+ mtc0 v0, psr // restore old R4000 Status Register
+ nop
+ nop
+ nop
+ nop
+
+ .set reorder
+
+ j ra // return
+
+ .end HalpDisableTimeoutInterrupts
+
+ SBTTL("Enable Timeout Interrupts")
+//++
+//
+// ULONG
+// HalpEnableTimeoutInterrupts(
+// VOID
+// )
+//
+// Routine Description:
+//
+// This function is the Counterpart of HalpDisableTimeoutInterrupts
+// We hope, it is never called
+//
+// Note: Because the SNI ASIC is located at a special Address,
+// ( I have to study the docs again ...)
+// We have to set the Disable Parity Error and ECC Detection Bit in the
+// R4x00 Status register
+//
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// The value of the Status register.
+//
+//--
+
+ LEAF_ENTRY(HalpEnableTimeoutInterrupts)
+
+ .set noreorder
+ mfc0 v0,psr // get current PSR
+ nop // fill
+ nop
+ nop
+ or v1, v0, STATUS_DE // disable Parity/ Cache errors
+ and v1, v1, ~(STATUS_IE) // disable Interrupts
+ mtc0 v1, psr
+ nop
+ nop
+ nop
+ li t0, IOMEMCONF_ADDR // Timeout (and other) register
+ lw a0, 0(t0) // get the current value
+ or a1, a0, 0x00200000 // set bit 21
+ sw a1, 0(t0) // set register
+ sync // flush write buffers
+
+ mtc0 v0, psr // restore old R4000 Status Register
+ nop
+ nop
+ nop
+
+ .set reorder
+
+ j ra // return
+
+ .end HalpEnableTimeoutInterrupts
+
+#endif
+
diff --git a/private/ntos/nthals/halsni4x/mips/x4tb.s b/private/ntos/nthals/halsni4x/mips/x4tb.s
new file mode 100644
index 000000000..2728c10ea
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/x4tb.s
@@ -0,0 +1,110 @@
+#if defined(R4000)
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk35/src/hal/halsni/mips/RCS/x4tb.s,v 1.2 1994/12/01 15:18:29 holli 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/halsni4x/mips/x86bios.c b/private/ntos/nthals/halsni4x/mips/x86bios.c
new file mode 100644
index 000000000..17cd688aa
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/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/halsni4x/mips/xxcache.c b/private/ntos/nthals/halsni4x/mips/xxcache.c
new file mode 100644
index 000000000..0bf8143ae
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/xxcache.c
@@ -0,0 +1,399 @@
+#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk35/src/hal/halsni/mips/RCS/xxcache.c,v 1.4 1995/04/07 10:02:52 flo 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"
+
+HalpProcessorType HalpProcessorId = UNKNOWN;
+
+//
+// Prototypes for private functions
+// they match the ones defined for the HAL ...
+// they diffrentiate in ending Uni/Multi
+//
+
+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
+ );
+
+
+VOID
+HalpProcessorConfig()
+{
+
+ if (HalpOrionIdentify() == HalpR4600) {
+ HalpProcessorId = ORIONSC;
+ return;
+ }
+
+ if (HalpMpAgentIdentify() == TRUE) {
+ HalpProcessorId = MPAGENT;
+ return;
+ }
+
+ HalpProcessorId = R4x00;
+
+ 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/halsni4x/mips/xxcalstl.c b/private/ntos/nthals/halsni4x/mips/xxcalstl.c
new file mode 100644
index 000000000..a3a883da5
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/xxcalstl.c
@@ -0,0 +1,270 @@
+#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk351/src/hal/halsni4x/mips/RCS/xxcalstl.c,v 1.2 1995/10/06 09:42:11 flo 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"
+
+
+//
+// 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;
+ 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/halsni4x/mips/xxclock.c b/private/ntos/nthals/halsni4x/mips/xxclock.c
new file mode 100644
index 000000000..0016c5194
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/xxclock.c
@@ -0,0 +1,233 @@
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk35/src/hal/halsni/mips/RCS/xxclock.c,v 1.3 1995/02/13 12:54:54 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) RM400_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);
+
+}
+
diff --git a/private/ntos/nthals/halsni4x/mips/xxidle.s b/private/ntos/nthals/halsni4x/mips/xxidle.s
new file mode 100644
index 000000000..44ae154f7
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/xxidle.s
@@ -0,0 +1,78 @@
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk35/src/hal/halsni/mips/RCS/xxidle.s,v 1.5 1995/04/07 10:04:26 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.
+//
+
+ j HalpCheckSpuriousInt // return
+
+ .end HalProcessorIdle
+
diff --git a/private/ntos/nthals/halsni4x/mips/xxinithl.c b/private/ntos/nthals/halsni4x/mips/xxinithl.c
new file mode 100644
index 000000000..8e05dea91
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/xxinithl.c
@@ -0,0 +1,746 @@
+#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk351/src/hal/halsni4x/mips/RCS/xxinithl.c,v 1.4 1995/10/06 09:40:49 flo 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"
+
+
+#if DBG
+UCHAR HalpBuffer[128];
+#endif
+
+VOID HalpNetTowerInit(IN PLOADER_PARAMETER_BLOCK LoaderBlock);
+
+typedef struct _HALP_NET_CONFIG {
+ UCHAR Reserved[2];
+ UCHAR SysBus; // 54
+ UCHAR Reserved1[5];
+ ULONG PISCP; // adress ISCP
+ UCHAR Busy;
+ UCHAR Reserved2[3];
+ ULONG PSCB; // adress SCB
+ USHORT Status;
+ USHORT Command;
+ ULONG Reseved3[9];
+} HALP_NET_CONFIG, *PHALP_NET_CONFIG;
+
+ULONG HalpNetReserved[18];
+
+ULONG HalpLedRegister;
+PUCHAR HalpLedAddress = (PUCHAR)RM400_LED_ADDR;
+ULONG HalpBusType = MACHINE_TYPE_ISA;
+//ULONG HalpBusType = MACHINE_TYPE_EISA;
+ULONG HalpMapBufferSize;
+PHYSICAL_ADDRESS HalpMapBufferPhysicalAddress;
+PHALP_NET_CONFIG HalpNetStructureAddress;
+BOOLEAN LessThan16Mb;
+BOOLEAN HalpEisaDma;
+BOOLEAN HalpProcPc = TRUE; // kind of CPU module (without second. cache)
+BOOLEAN HalpEisaExtensionInstalled = FALSE;
+BOOLEAN HalpIsRM200 = FALSE;
+MotherBoardType HalpMainBoard = M8042; // default is RM400 Minitower
+
+
+BOOLEAN HalpIsMulti = FALSE; // MultiProcessor machine has a MpAgent per processor
+BOOLEAN HalpCountCompareInterrupt = FALSE;
+KAFFINITY HalpActiveProcessors;
+LONG HalpNetProcessor = 0;
+
+//
+// Define global spin locks used to synchronize various HAL operations.
+//
+
+KSPIN_LOCK HalpBeepLock;
+KSPIN_LOCK HalpDisplayAdapterLock;
+KSPIN_LOCK HalpSystemInterruptLock;
+
+//
+// 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;
+ UCHAR Byte;
+ PRESTART_BLOCK NextRestartBlock;
+
+ Prcb = PCR->Prcb;
+
+ 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);
+ }
+
+ if ( (LoaderBlock->u.Mips.SecondLevelDcacheSize) == 0 )
+ HalpProcPc = TRUE;
+ else
+ HalpProcPc = FALSE;
+
+ //
+ // Processor 0 specific
+ //
+
+ if(Prcb->Number == 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);
+
+ //
+ // Set address of cache error routine.
+ //
+
+ KeSetCacheErrorRoutine(HalpCacheErrorRoutine);
+
+ //
+ // try to identify the Kind of Mainboard
+ //
+
+ HalpMainBoard = (MotherBoardType) READ_REGISTER_UCHAR(0xbff0002a);
+
+ if (HalpMainBoard == M8036) {
+
+ //
+ // this is the "nice" Desktop Model RM200
+ //
+ HalpIsRM200 = TRUE;
+
+ //
+ // test, if the EISA Extension board is installed in the desktop
+ //
+
+ Byte = READ_REGISTER_UCHAR(RM200_INTERRUPT_SOURCE_REGISTER);
+
+ // this bit is low active
+
+ if ((Byte & 0x80) == 0)
+ HalpEisaExtensionInstalled = TRUE;
+
+ //
+ // enable all Interrupts by resetting there bits in the interrupt mask register
+ // except Timeout interrupts, which we don't like at this moment
+ //
+
+ // WRITE_REGISTER_UCHAR(RM200_INTERRUPT_MASK_REGISTER, (UCHAR)(RM200_TIMEOUT_MASK));
+ WRITE_REGISTER_UCHAR(RM200_INTERRUPT_MASK_REGISTER, (UCHAR)(0x00));
+
+ }
+
+
+ HalpLedRegister = 0;
+ HalpLedAddress = (HalpIsRM200) ? (PUCHAR)RM200_LED_ADDR : (PUCHAR)RM400_LED_ADDR;
+
+ //
+ // for Isa/Eisa access during phase 0 we use KSEG1 addresses
+ // N.B. HalpEisaExtensionInstalled can only be TRUE on an RM200 (Desktop)
+ //
+
+ if (HalpEisaExtensionInstalled )
+ HalpOnboardControlBase = (PVOID) (RM200_ONBOARD_CONTROL_PHYSICAL_BASE | KSEG1_BASE);
+
+ else
+
+ HalpOnboardControlBase = (PVOID) (EISA_CONTROL_PHYSICAL_BASE | KSEG1_BASE);
+
+ HalpEisaControlBase = (PVOID) (EISA_CONTROL_PHYSICAL_BASE | KSEG1_BASE);
+
+ //
+ // Initialize the display adapter.
+ //
+
+ HalpInitializeDisplay0(LoaderBlock);
+
+ //
+ // 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
+ //
+
+ HalpIsMulti = TRUE;
+ NextRestartBlock->BootStatus.ProcessorStart = 1;
+ NextRestartBlock->BootStatus.ProcessorReady = 1;
+
+ //
+ // set up Interrupt routing, Cache replace Address etc.
+ //
+
+ PCR->InterruptRoutine[OUR_IPI_LEVEL] = HalpIpiInterrupt;
+
+ } else {
+#if DBG
+ HalDisplayString("UniProcessor machine detected\n");
+#endif
+ HalpIsMulti = FALSE;
+ }
+
+ // Initialize the MP Agent
+
+ if (HalpProcessorId == MPAGENT) {
+ HalpInitMPAgent(0);
+ HalpActiveProcessors = 0x01;
+ }
+
+ //
+ // For the moment, we say all Eisa/ Isa(Onboard) Interrupts should go to processor 0
+ //
+
+ HalpCreateEisaStructures(Isa); // Initialize Onboard Interrupts and Controller
+
+ //
+ // The RM200 is in Fact a real Uni Processor machine
+ //
+
+ if(HalpEisaExtensionInstalled) {
+ HalpCreateEisaStructures(Eisa); // Initialize Eisa Extension board Interrupts
+ // and Controller for the RM200
+ }
+
+ // Correction pb Tower with memory > 128 mb + minitower with adaptec
+
+ if ((HalpMainBoard == M8032) || (HalpMainBoard == M8042))
+ HalpNetTowerInit(LoaderBlock);
+
+ //
+ // Initialize SNI specific interrupts
+ // (only once needed)
+ //
+
+ if (HalpProcessorId == MPAGENT) HalpCreateIntMultiStructures(); else HalpCreateIntStructures();
+
+ } 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();
+
+ 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
+ //
+
+ if ((HalpProcPc) || ((HalpProcessorId == ORIONSC) && (HalpMainBoard != M8036)))
+ 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 (Number == 0)
+ return;
+
+#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)
+//
+ HalpActiveProcessors |= (1 << (NextRestartBlock->ProcessorId));
+ HalpSendIpi(1 << (NextRestartBlock->ProcessorId), MPA_BOOT_MESSAGE );
+ HalpNetProcessor = 1; // If proc 1 started, net interrupts will be connected to it
+ 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");
+ HalDisplayString("ºMicrosoft(R) Windows NT(TM) 3.51 Hardware Abstraction Layer º\n");
+ HalDisplayString("ºfor Siemens Nixdorf RM200/RM400 Release 2.0 B0006 º\n");
+ HalDisplayString("ºCopyright(c) Siemens Nixdorf Informationssysteme AG 1995 º\n");
+ HalDisplayString("ºCopyright(c) Microsoft Corporation 1985-1995 º\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");
+
+ }
+
+
+}
+
+
+
+VOID
+HalpNetTowerInit(
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ )
+/*++
+
+Routine Description:
+
+ This function is only used on Tower machines. It initialises the net chip.
+ It is used because of a hardware problem when the machine has
+ more than 128 Mb memory : net interrupts may happen with no
+ installed network.
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+ULONG Cmd;
+PUSHORT Port = (PUSHORT)0xb8000000;
+PULONG ChannelAttention = (PULONG)0xb8010000;
+ULONG Time;
+USHORT Status;
+
+ HalpNetStructureAddress =
+ (PHALP_NET_CONFIG) (((ULONG)((PUCHAR)HalpNetReserved + 0xf)) & 0xfffffff0); // aligned on 16
+ HalpNetStructureAddress = (PHALP_NET_CONFIG) ((ULONG)HalpNetStructureAddress | 0xa0000000);
+ HalSweepDcache(); // because we are going to use non cached addresses
+ HalpNetStructureAddress->SysBus = 0x54;
+ HalpNetStructureAddress->Busy = 0xff;
+ HalpNetStructureAddress->PISCP = (ULONG)(((PULONG)HalpNetStructureAddress) + 3) & 0x5fffffff;
+ HalpNetStructureAddress->PSCB = (ULONG)(((PULONG)HalpNetStructureAddress) + 5) & 0x5fffffff;
+
+ Cmd = 0;
+ WRITE_REGISTER_USHORT(Port, (USHORT)Cmd);
+ WRITE_REGISTER_USHORT(Port, (USHORT)Cmd);
+ KeStallExecutionProcessor(50000);
+
+ Cmd = (((ULONG)HalpNetStructureAddress) & 0x5fffffff) | 0x02;
+ WRITE_REGISTER_USHORT(Port, (USHORT)Cmd);
+ WRITE_REGISTER_USHORT(Port, (USHORT)(Cmd >> 16));
+
+ Cmd = 0;
+ WRITE_REGISTER_ULONG(ChannelAttention,Cmd);
+
+ Time = 20;
+ while (Time > 0) {
+ if (!(HalpNetStructureAddress->Busy !=0)) {
+ break;
+ }
+ KeStallExecutionProcessor(10000);
+ Time--;
+ }
+
+ Status = HalpNetStructureAddress->Status;
+ Status = Status & 0xf000;
+ HalpNetStructureAddress->Command = Status;
+ KeFlushWriteBuffer();
+
+ Cmd = 0;
+ WRITE_REGISTER_ULONG(ChannelAttention,Cmd);
+}
diff --git a/private/ntos/nthals/halsni4x/mips/xxinitnt.c b/private/ntos/nthals/halsni4x/mips/xxinitnt.c
new file mode 100644
index 000000000..2d34c4c38
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/xxinitnt.c
@@ -0,0 +1,369 @@
+#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk35/src/hal/halsni/mips/RCS/xxinitnt.c,v 1.6 1995/04/07 10:08:17 flo 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 HalpProcPc;
+extern BOOLEAN HalpCountCompareInterrupt;
+
+
+//
+// Define forward referenced prototypes.
+//
+
+VOID
+HalpAckExtraClockInterrupt(
+ VOID
+ );
+
+VOID
+HalpCountInterrupt (
+ VOID
+ );
+
+VOID
+HalpProgramIntervalTimer (
+ IN ULONG Interval
+ );
+
+VOID
+HalpProgramExtraTimer (
+ 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 for R4x00 SC machines
+ | | | | +-------------------- SCSI_EISA LEVEL
+ | | | +------------------------ DUART (Console)
+ | | +---------------------------- TIMER (82C54 in the local I/O part)
+ | +-------------------------------- Ethernet (intel 82596 onboard)
+ +------------------------------------ CountCompare (Profiling) or PushButton Int.
+
+---*/
+
+//
+// On an R4x00SC, the processor has only 1 central interrupt pin, so all
+// should be directed to this interrupt, except the (internal) CountCompare interrupt
+// This is also true for the oncomming SNI Desktop model, which has only the
+// central interrupt connected
+//
+
+UCHAR
+HalpIrqlMask_SC[] = {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_SC[] = {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 an R4x00MC, all the interrupts enable/disable per processor is managed by the MPagent
+//
+
+/*+++ Note from Dave Cutler "Mr. NT"
+
+| How can this happen ?
+|
+
+You cannot use the interrupt mask field of the status register to
+enable/disable per processor interrupts. In fact, the IRQL mask table
+that is initialized by the HAL must be the same for all processors.
+
+When threads start execution they have all interrupts in the
+interrupt mask field set according to the PASSIVE_LEVEL entry in the
+interrupt mapping table of the processor they start on. They are
+immediately context switchable. If per processor interrupts weere
+controlled by the interrupt mask field of the status register, then
+as soon as the thread got scheduled on another processor, the enables
+would no longer be correct.
+
+d
+
+---*/
+
+UCHAR HalpIrqlMask_MC[] = {4, 7, 6, 7, 5, 7, 6, 7, // 0000 - 0111 high 4-bits
+ 8, 8, 8, 8, 8, 8, 8, 8, // 1000 - 1111 high 4-bits
+ 0, 1, 2, 2, 3, 3, 3, 3, // 0000 - 0111 low 4-bits
+ 4, 4, 4, 4, 4, 4, 4, 4}; // 1000 - 1111 low 4-bits
+
+
+UCHAR HalpIrqlTable_MC[] = {0xff, // IRQL 0
+ 0xfe, // IRQL 1
+ 0xfc, // IRQL 2
+ 0xf8, // IRQL 3
+ 0xf0, // IRQL 4
+ 0xb0, // IRQL 5 NET
+ 0x90, // IRQL 6 CLOCK
+ 0x80, // IRQL 7 IPI
+ 0x00}; // IRQL 8
+
+UCHAR
+HalpIrqlMask_PC[] = {4, 5, 6, 6, 7, 7, 7, 7, // 0000 - 0111 high 4-bits
+ 8, 8, 8, 8, 8, 8, 8, 8, // 1000 - 1111 high 4-bits
+ 0, 1, 2, 2, 3, 3, 3, 3, // 0000 - 0111 low 4-bits
+ 4, 4, 4, 4, 4, 4, 4, 4}; // 1000 - 1111 low 4-bits
+
+UCHAR
+HalpIrqlTable_PC[] = {0xfb, // IRQL 0 1111 1011
+ 0xfa, // IRQL 1 1111 1010
+ 0xf8, // IRQL 2 1111 1000
+ 0xf8, // IRQL 3 1111 1000
+ 0xf0, // IRQL 4 1111 0000
+ 0xe0, // IRQL 5 1110 0000
+ 0xc0, // IRQL 6 1100 0000
+ 0x80, // IRQL 7 1000 0000
+ 0x00}; // IRQL 8 0000 0000
+
+
+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 (HalpIsRM200) {
+
+ //
+ // On an RM200 (Desktop) we have only 1 interrupt, which is like
+ // the central Interrupt for R4x00SC machines
+ //
+
+ for (Index = 0; Index < sizeof(HalpIrqlMask_SC); Index += 1)
+ PCR->IrqlMask[Index] = HalpIrqlMask_SC[Index];
+
+ for (Index = 0; Index < sizeof(HalpIrqlTable_SC); Index += 1)
+
+ PCR->IrqlTable[Index] = HalpIrqlTable_SC[Index];
+
+ } else {
+
+ //
+ // if this is not a Desktop, we have to check if this is an
+ // R4x00 SC model or a R4x00 MC (multiprocessor model)
+ //
+
+ if (HalpProcessorId == MPAGENT) {
+
+ //
+ // this is the boot processor in an MultiProcessor Environment
+ //
+
+ for (Index = 0; Index < sizeof(HalpIrqlMask_MC); Index += 1)
+ PCR->IrqlMask[Index] = HalpIrqlMask_MC[Index];
+ for (Index = 0; Index < sizeof(HalpIrqlTable_MC); Index += 1)
+ PCR->IrqlTable[Index] = HalpIrqlTable_MC[Index];
+
+ } else {
+
+ if ((HalpProcPc) || (HalpProcessorId == ORIONSC)) {
+
+ //
+ // this is an R4000PC or a R4600 model in an UniProcessor Environment
+ //
+
+ for (Index = 0; Index < sizeof(HalpIrqlMask_PC); Index += 1)
+ PCR->IrqlMask[Index] = HalpIrqlMask_PC[Index];
+ for (Index = 0; Index < sizeof(HalpIrqlTable_PC); Index += 1)
+ PCR->IrqlTable[Index] = HalpIrqlTable_PC[Index];
+
+ } else {
+
+ //
+ // this is an R4x00SC model in an UniProcessor Environment
+ //
+
+ for (Index = 0; Index < sizeof(HalpIrqlMask_SC); Index += 1)
+ PCR->IrqlMask[Index] = HalpIrqlMask_SC[Index];
+ for (Index = 0; Index < sizeof(HalpIrqlTable_SC); Index += 1)
+ PCR->IrqlTable[Index] = HalpIrqlTable_SC[Index];
+ }
+
+ }
+ }
+
+ //
+ // the main system clock is always in the onboard PC core
+ //
+
+ PCR->InterruptRoutine[CLOCK2_LEVEL] = (PKINTERRUPT_ROUTINE)HalpStallInterrupt;
+
+ //
+ // 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.
+ //
+
+
+
+ //
+ // force a CountCompare interrupt
+ //
+
+ HalpWriteCompareRegisterAndClear(100);
+
+ PCR->InterruptRoutine[PROFILE_LEVEL] = HalpCountInterrupt;
+
+ HalpProgramIntervalTimer (MAXIMUM_INCREMENT);
+ HalpEnableOnboardInterrupt(CLOCK2_LEVEL,Latched); // Enable Timer1,Counter0 interrupt
+
+ } else {
+
+ //
+ // MultiProcessorEnvironment Processor N
+ //
+
+ for (Index = 0; Index < sizeof(HalpIrqlMask_MC); Index += 1)
+ PCR->IrqlMask[Index] = HalpIrqlMask_MC[Index];
+ for (Index = 0; Index < sizeof(HalpIrqlTable_MC); Index += 1)
+ PCR->IrqlTable[Index] = HalpIrqlTable_MC[Index];
+
+ 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/halsni4x/mips/xxipiint.s b/private/ntos/nthals/halsni4x/mips/xxipiint.s
new file mode 100644
index 000000000..fbdb99fd5
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/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/halsni4x/mips/xxmemory.c b/private/ntos/nthals/halsni4x/mips/xxmemory.c
new file mode 100644
index 000000000..3a9063157
--- /dev/null
+++ b/private/ntos/nthals/halsni4x/mips/xxmemory.c
@@ -0,0 +1,179 @@
+//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk35/src/hal/halsni/mips/RCS/xxmemory.c,v 1.2 1994/11/09 07:54:26 holli 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;
+}