From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/ntos/nthals/halsni4x/drivesup.c | 7 + private/ntos/nthals/halsni4x/hal.rc | 17 + private/ntos/nthals/halsni4x/hal.src | 7 + private/ntos/nthals/halsni4x/makefile | 6 + private/ntos/nthals/halsni4x/makefile.inc | 5 + private/ntos/nthals/halsni4x/mips/allstart.c | 59 + private/ntos/nthals/halsni4x/mips/cacherr.s | 196 ++ private/ntos/nthals/halsni4x/mips/deskdef.h | 93 + private/ntos/nthals/halsni4x/mips/duocache.s | 774 +++++++ private/ntos/nthals/halsni4x/mips/halp.h | 161 ++ private/ntos/nthals/halsni4x/mips/i82c54.h | 34 + private/ntos/nthals/halsni4x/mips/j4cache.s | 1064 ++++++++++ private/ntos/nthals/halsni4x/mips/j4flshbf.s | 53 + private/ntos/nthals/halsni4x/mips/j4flshio.c | 202 ++ private/ntos/nthals/halsni4x/mips/j4prof.c | 325 +++ private/ntos/nthals/halsni4x/mips/jxbeep.c | 132 ++ private/ntos/nthals/halsni4x/mips/jxebsup.c | 2851 ++++++++++++++++++++++++++ private/ntos/nthals/halsni4x/mips/jxenvirv.c | 192 ++ private/ntos/nthals/halsni4x/mips/jxhwsup.c | 2437 ++++++++++++++++++++++ private/ntos/nthals/halsni4x/mips/jxmapio.c | 133 ++ private/ntos/nthals/halsni4x/mips/jxport.c | 805 ++++++++ private/ntos/nthals/halsni4x/mips/jxreturn.c | 239 +++ private/ntos/nthals/halsni4x/mips/jxsysint.c | 380 ++++ private/ntos/nthals/halsni4x/mips/jxtime.c | 334 +++ private/ntos/nthals/halsni4x/mips/jxusage.c | 47 + private/ntos/nthals/halsni4x/mips/minidef.h | 141 ++ private/ntos/nthals/halsni4x/mips/mpagent.c | 681 ++++++ private/ntos/nthals/halsni4x/mips/mpagent.h | 535 +++++ private/ntos/nthals/halsni4x/mips/orcache.s | 628 ++++++ private/ntos/nthals/halsni4x/mips/r4intdsp.c | 1052 ++++++++++ private/ntos/nthals/halsni4x/mips/snidef.h | 215 ++ private/ntos/nthals/halsni4x/mips/snidisp.c | 1475 +++++++++++++ private/ntos/nthals/halsni4x/mips/snihalp.h | 338 +++ private/ntos/nthals/halsni4x/mips/sniregs.h | 139 ++ private/ntos/nthals/halsni4x/mips/unicache.s | 1098 ++++++++++ private/ntos/nthals/halsni4x/mips/vgadata.h | 406 ++++ private/ntos/nthals/halsni4x/mips/x4clock.s | 325 +++ private/ntos/nthals/halsni4x/mips/x4misc.s | 472 +++++ private/ntos/nthals/halsni4x/mips/x4tb.s | 110 + private/ntos/nthals/halsni4x/mips/x86bios.c | 191 ++ private/ntos/nthals/halsni4x/mips/xxcache.c | 399 ++++ private/ntos/nthals/halsni4x/mips/xxcalstl.c | 270 +++ private/ntos/nthals/halsni4x/mips/xxclock.c | 233 +++ private/ntos/nthals/halsni4x/mips/xxidle.s | 78 + private/ntos/nthals/halsni4x/mips/xxinithl.c | 746 +++++++ private/ntos/nthals/halsni4x/mips/xxinitnt.c | 369 ++++ private/ntos/nthals/halsni4x/mips/xxipiint.s | 56 + private/ntos/nthals/halsni4x/mips/xxmemory.c | 179 ++ private/ntos/nthals/halsni4x/sources | 91 + 49 files changed, 20780 insertions(+) create mode 100644 private/ntos/nthals/halsni4x/drivesup.c create mode 100644 private/ntos/nthals/halsni4x/hal.rc create mode 100644 private/ntos/nthals/halsni4x/hal.src create mode 100644 private/ntos/nthals/halsni4x/makefile create mode 100644 private/ntos/nthals/halsni4x/makefile.inc create mode 100644 private/ntos/nthals/halsni4x/mips/allstart.c create mode 100644 private/ntos/nthals/halsni4x/mips/cacherr.s create mode 100644 private/ntos/nthals/halsni4x/mips/deskdef.h create mode 100644 private/ntos/nthals/halsni4x/mips/duocache.s create mode 100644 private/ntos/nthals/halsni4x/mips/halp.h create mode 100644 private/ntos/nthals/halsni4x/mips/i82c54.h create mode 100644 private/ntos/nthals/halsni4x/mips/j4cache.s create mode 100644 private/ntos/nthals/halsni4x/mips/j4flshbf.s create mode 100644 private/ntos/nthals/halsni4x/mips/j4flshio.c create mode 100644 private/ntos/nthals/halsni4x/mips/j4prof.c create mode 100644 private/ntos/nthals/halsni4x/mips/jxbeep.c create mode 100644 private/ntos/nthals/halsni4x/mips/jxebsup.c create mode 100644 private/ntos/nthals/halsni4x/mips/jxenvirv.c create mode 100644 private/ntos/nthals/halsni4x/mips/jxhwsup.c create mode 100644 private/ntos/nthals/halsni4x/mips/jxmapio.c create mode 100644 private/ntos/nthals/halsni4x/mips/jxport.c create mode 100644 private/ntos/nthals/halsni4x/mips/jxreturn.c create mode 100644 private/ntos/nthals/halsni4x/mips/jxsysint.c create mode 100644 private/ntos/nthals/halsni4x/mips/jxtime.c create mode 100644 private/ntos/nthals/halsni4x/mips/jxusage.c create mode 100644 private/ntos/nthals/halsni4x/mips/minidef.h create mode 100644 private/ntos/nthals/halsni4x/mips/mpagent.c create mode 100644 private/ntos/nthals/halsni4x/mips/mpagent.h create mode 100644 private/ntos/nthals/halsni4x/mips/orcache.s create mode 100644 private/ntos/nthals/halsni4x/mips/r4intdsp.c create mode 100644 private/ntos/nthals/halsni4x/mips/snidef.h create mode 100644 private/ntos/nthals/halsni4x/mips/snidisp.c create mode 100644 private/ntos/nthals/halsni4x/mips/snihalp.h create mode 100644 private/ntos/nthals/halsni4x/mips/sniregs.h create mode 100644 private/ntos/nthals/halsni4x/mips/unicache.s create mode 100644 private/ntos/nthals/halsni4x/mips/vgadata.h create mode 100644 private/ntos/nthals/halsni4x/mips/x4clock.s create mode 100644 private/ntos/nthals/halsni4x/mips/x4misc.s create mode 100644 private/ntos/nthals/halsni4x/mips/x4tb.s create mode 100644 private/ntos/nthals/halsni4x/mips/x86bios.c create mode 100644 private/ntos/nthals/halsni4x/mips/xxcache.c create mode 100644 private/ntos/nthals/halsni4x/mips/xxcalstl.c create mode 100644 private/ntos/nthals/halsni4x/mips/xxclock.c create mode 100644 private/ntos/nthals/halsni4x/mips/xxidle.s create mode 100644 private/ntos/nthals/halsni4x/mips/xxinithl.c create mode 100644 private/ntos/nthals/halsni4x/mips/xxinitnt.c create mode 100644 private/ntos/nthals/halsni4x/mips/xxipiint.s create mode 100644 private/ntos/nthals/halsni4x/mips/xxmemory.c create mode 100644 private/ntos/nthals/halsni4x/sources (limited to 'private/ntos/nthals/halsni4x') diff --git a/private/ntos/nthals/halsni4x/drivesup.c b/private/ntos/nthals/halsni4x/drivesup.c new file mode 100644 index 000000000..38259e5f4 --- /dev/null +++ b/private/ntos/nthals/halsni4x/drivesup.c @@ -0,0 +1,7 @@ +// +// This file simply includes the common sources from the current HAL +// directory. When the structure is finally changed, the real file should +// be in this directory. +// + +#include "..\drivesup.c" diff --git a/private/ntos/nthals/halsni4x/hal.rc b/private/ntos/nthals/halsni4x/hal.rc new file mode 100644 index 000000000..73b67f096 --- /dev/null +++ b/private/ntos/nthals/halsni4x/hal.rc @@ -0,0 +1,17 @@ +#include + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "SNI RM200/RM400 Hardware Abstraction Layer DLL" +#define VER_INTERNALNAME_STR "hal.dll" +#if defined(SNI_INTERNAL) +#define VER_FILEVERSION_STR "2.0 A0008" +#include "vlbsupp.ver" +#else +#define VER_FILEVERSION_STR "2.0 B0008" +#endif +#include "common.ver" + + diff --git a/private/ntos/nthals/halsni4x/hal.src b/private/ntos/nthals/halsni4x/hal.src new file mode 100644 index 000000000..da778bb9d --- /dev/null +++ b/private/ntos/nthals/halsni4x/hal.src @@ -0,0 +1,7 @@ +// +// This file simply includes the common sources from the current HAL +// directory. When the structure is finally changed, the real file should +// be in this directory. +// + +#include "..\hal.src" diff --git a/private/ntos/nthals/halsni4x/makefile b/private/ntos/nthals/halsni4x/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/ntos/nthals/halsni4x/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/ntos/nthals/halsni4x/makefile.inc b/private/ntos/nthals/halsni4x/makefile.inc new file mode 100644 index 000000000..15c0bae90 --- /dev/null +++ b/private/ntos/nthals/halsni4x/makefile.inc @@ -0,0 +1,5 @@ +obj\mips\hal.def: hal.src + rcpp -P -f hal.src -DMIPS=1 $(C_DEFINES) -g obj\mips\hal.def + +$(TARGETPATH)\mips\hal.lib: $(TARGETPATH)\mips\halsni4x.lib + copy $** $@ 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>= 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; +} diff --git a/private/ntos/nthals/halsni4x/sources b/private/ntos/nthals/halsni4x/sources new file mode 100644 index 000000000..491d21b3c --- /dev/null +++ b/private/ntos/nthals/halsni4x/sources @@ -0,0 +1,91 @@ +!IF 0 + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + + +!ENDIF + +MAJORCOMP=ntos +MINORCOMP=hal + +TARGETNAME=halsni4x +TARGETPATH=$(BASEDIR)\public\sdk\lib +TARGETLIBS=$(BASEDIR)\private\ntos\nthals\x86new\obj\mips\x86new.lib \ + $(BASEDIR)\public\sdk\lib\*\libcntpr.lib + +!IF $(MIPS) + +TARGETTYPE=HAL + +!ELSE + +TARGETTYPE=DRIVER + +!ENDIF + +C_DEFINES=-DSNI -DORION + +INCLUDES=..\x86new;..\..\inc + +MIPS_ENABLE_MIPS3=1 + +MSC_WARNING_LEVEL=/W3 /WX + +SOURCES= + +MIPS_SOURCES=hal.rc \ + drivesup.c \ + mips\x86bios.c \ + mips\allstart.c \ + mips\cacherr.s \ + mips\unicache.s \ + mips\duocache.s \ + mips\orcache.s \ + mips\j4flshbf.s \ + mips\j4flshio.c \ + mips\j4prof.c \ + mips\jxebsup.c \ + mips\jxenvirv.c \ + mips\jxport.c \ + mips\jxbeep.c \ + mips\jxreturn.c \ + mips\jxmapio.c \ + mips\SNIdisp.c \ + mips\jxhwsup.c \ + mips\jxsysint.c \ + mips\jxtime.c \ + mips\jxusage.c \ + mips\xxcalstl.c \ + mips\xxinithl.c \ + mips\xxinitnt.c \ + mips\r4intdsp.c \ + mips\xxmemory.c \ + mips\mpagent.c \ + mips\xxcache.c \ + mips\xxclock.c \ + mips\xxidle.s \ + mips\x4misc.s \ + mips\xxipiint.s \ + mips\x4clock.s \ + mips\xxipiint.s \ + mips\x4tb.s + +DLLDEF=obj\*\hal.def + +!IF $(MIPS) + +NTTARGETFILES=$(TARGETPATH)\mips\hal.lib + +!ENDIF -- cgit v1.2.3