summaryrefslogtreecommitdiffstats
path: root/private/ntos/nthals/hal0jens
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/nthals/hal0jens')
-rw-r--r--private/ntos/nthals/hal0jens/alpha/allstart.c55
-rw-r--r--private/ntos/nthals/hal0jens/alpha/axebsup.c786
-rw-r--r--private/ntos/nthals/hal0jens/alpha/axibsup.c1089
-rw-r--r--private/ntos/nthals/hal0jens/alpha/axlbsup.c84
-rw-r--r--private/ntos/nthals/hal0jens/alpha/axsysint.c473
-rw-r--r--private/ntos/nthals/hal0jens/alpha/bios.c105
-rw-r--r--private/ntos/nthals/hal0jens/alpha/ev4ints.s6
-rw-r--r--private/ntos/nthals/hal0jens/alpha/ev4prof.c7
-rw-r--r--private/ntos/nthals/hal0jens/alpha/halp.h223
-rw-r--r--private/ntos/nthals/hal0jens/alpha/halpal.s184
-rw-r--r--private/ntos/nthals/hal0jens/alpha/halvga.h72
-rw-r--r--private/ntos/nthals/hal0jens/alpha/idle.s62
-rw-r--r--private/ntos/nthals/hal0jens/alpha/jenfonts.h231
-rw-r--r--private/ntos/nthals/hal0jens/alpha/jxbeep.c133
-rw-r--r--private/ntos/nthals/hal0jens/alpha/jxcache.c521
-rw-r--r--private/ntos/nthals/hal0jens/alpha/jxcalstl.c148
-rw-r--r--private/ntos/nthals/hal0jens/alpha/jxclock.c311
-rw-r--r--private/ntos/nthals/hal0jens/alpha/jxdisp.c752
-rw-r--r--private/ntos/nthals/hal0jens/alpha/jxenv.h160
-rw-r--r--private/ntos/nthals/hal0jens/alpha/jxhalp.h188
-rw-r--r--private/ntos/nthals/hal0jens/alpha/jxhltsup.s109
-rw-r--r--private/ntos/nthals/hal0jens/alpha/jxhwsup.c4290
-rw-r--r--private/ntos/nthals/hal0jens/alpha/jxinfo.c142
-rw-r--r--private/ntos/nthals/hal0jens/alpha/jxinitnt.c471
-rw-r--r--private/ntos/nthals/hal0jens/alpha/jxintsup.s205
-rw-r--r--private/ntos/nthals/hal0jens/alpha/jxioacc.s3523
-rw-r--r--private/ntos/nthals/hal0jens/alpha/jxiouser.c971
-rw-r--r--private/ntos/nthals/hal0jens/alpha/jxirql.h133
-rw-r--r--private/ntos/nthals/hal0jens/alpha/jxisa.h95
-rw-r--r--private/ntos/nthals/hal0jens/alpha/jxmapio.c86
-rw-r--r--private/ntos/nthals/hal0jens/alpha/jxmchk.c338
-rw-r--r--private/ntos/nthals/hal0jens/alpha/jxport.c604
-rw-r--r--private/ntos/nthals/hal0jens/alpha/jxprof.h77
-rw-r--r--private/ntos/nthals/hal0jens/alpha/jxprom.c1098
-rw-r--r--private/ntos/nthals/hal0jens/alpha/jxprom.h218
-rw-r--r--private/ntos/nthals/hal0jens/alpha/jxserp.h181
-rw-r--r--private/ntos/nthals/hal0jens/alpha/jxtime.c283
-rw-r--r--private/ntos/nthals/hal0jens/alpha/jxusage.c48
-rw-r--r--private/ntos/nthals/hal0jens/alpha/jxvtisup.s149
-rw-r--r--private/ntos/nthals/hal0jens/alpha/machdep.h42
-rw-r--r--private/ntos/nthals/hal0jens/alpha/xxenvirv.c1451
-rw-r--r--private/ntos/nthals/hal0jens/alpha/xxhalp.h74
-rw-r--r--private/ntos/nthals/hal0jens/alpha/xxinithl.c606
-rw-r--r--private/ntos/nthals/hal0jens/alpha/xxmemory.c168
-rw-r--r--private/ntos/nthals/hal0jens/alpha/xxreturn.c120
-rw-r--r--private/ntos/nthals/hal0jens/drivesup.c7
-rw-r--r--private/ntos/nthals/hal0jens/hal.rc11
-rw-r--r--private/ntos/nthals/hal0jens/hal.src7
-rw-r--r--private/ntos/nthals/hal0jens/makefile6
-rw-r--r--private/ntos/nthals/hal0jens/makefile.inc9
-rw-r--r--private/ntos/nthals/hal0jens/sources89
51 files changed, 21201 insertions, 0 deletions
diff --git a/private/ntos/nthals/hal0jens/alpha/allstart.c b/private/ntos/nthals/hal0jens/alpha/allstart.c
new file mode 100644
index 000000000..9bb5501bc
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/allstart.c
@@ -0,0 +1,55 @@
+/*++
+
+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.
+
+Author:
+
+ John Vert (jvert) 23-Jun-1994
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+
+BOOLEAN
+HalAllProcessorsStarted (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function executes platform specific operations that must be
+ performed after all processors have been started. It is called
+ for each processor in the host configuration.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ If platform specific operations are successful, then return TRUE.
+ Otherwise, return FALSE.
+
+--*/
+
+{
+ return TRUE;
+}
diff --git a/private/ntos/nthals/hal0jens/alpha/axebsup.c b/private/ntos/nthals/hal0jens/alpha/axebsup.c
new file mode 100644
index 000000000..b34b07320
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/axebsup.c
@@ -0,0 +1,786 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ axebsup.c
+
+Abstract:
+
+ The module provides the EISA bus support for Alpha/Jensen systems.
+
+Author:
+
+ Jeff Havens (jhavens) 19-Jun-1991
+ Miche Baker-Harvey (miche) 13-May-1992
+ Jeff McLeman (DEC) 1-Jun-1992
+
+Revision History:
+
+ 11-Mar-1993 Joe Mitchell (DEC)
+ Added support for NMI interrupts: Added interrupt service routine
+ HalHandleNMI. Added code to HalpCreateEisaStructures to initialize
+ NMI interrupts.
+
+ 22-Jul-1992 Jeff McLeman (mcleman)
+ Removed eisa xfer routines, since this is done in JXHWSUP
+
+ 02-Jul-92 Jeff McLeman (mcleman)
+ Removed alphadma.h header file. This file was not needed since
+ the DMA structure is described in the eisa header. Also add
+ a note describing eisa references in this module.
+
+ 13-May-92 Stole file jxebsup.c and converted for Alpha/Jensen
+
+
+--*/
+
+// ** note **
+// This module has routines that manipulate eisa on alpha machines. On
+// the jensen machine, this is done in jxhwsup.c . These routines
+// would be used for an alpha machine that had a local bus and an
+// eisa bus.
+//
+
+
+#include "halp.h"
+#include "jnsndef.h"
+#include "jnsnint.h"
+#include "eisa.h"
+
+//
+// Define the context structure for use by the interrupt routine.
+//
+
+typedef BOOLEAN (*PSECONDARY_DISPATCH)(
+ PVOID InterruptRoutine,
+ PKTRAP_FRAME TrapFrame
+ );
+
+//
+// Declare the interupt structure and spinlock for the intermediate EISA
+// interrupt dispachter.
+//
+
+KINTERRUPT HalpEisaInterrupt;
+
+/* [jrm 3/8/93] Add support for NMI interrupts */
+
+//
+// The following is the interrupt object used for DMA controller interrupts.
+// DMA controller interrupts occur when a memory parity error occurs or a
+// programming error occurs to the DMA controller.
+//
+
+KINTERRUPT HalpEisaNmiInterrupt;
+
+UCHAR EisaNMIMsg[] = "NMI: Eisa IOCHKERR board x\n";
+
+//
+// The following function is called when an EISA NMI occurs.
+//
+
+BOOLEAN
+HalHandleNMI(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext
+ );
+
+//
+// Define save area for ESIA adapter objects.
+//
+
+PADAPTER_OBJECT HalpEisaAdapter[8];
+
+//
+// Define save area for EISA interrupt mask registers and level\edge control
+// registers.
+//
+
+UCHAR HalpEisaInterrupt1Mask;
+UCHAR HalpEisaInterrupt2Mask;
+UCHAR HalpEisaInterrupt1Level;
+UCHAR HalpEisaInterrupt2Level;
+
+
+BOOLEAN
+HalpCreateEisaStructures (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the structures necessary for EISA operations
+ and connects the intermediate interrupt dispatcher. It also initializes the
+ EISA 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;
+
+ //
+ // Initialize the EISA NMI interrupt.
+ //
+
+ KeInitializeInterrupt( &HalpEisaNmiInterrupt,
+ HalHandleNMI,
+ NULL,
+ NULL,
+ EISA_NMI_VECTOR,
+ EISA_NMI_LEVEL,
+ EISA_NMI_LEVEL,
+ LevelSensitive,
+ FALSE,
+ 0,
+ FALSE
+ );
+
+ //
+ // Don't fail if the interrupt cannot be connected.
+ //
+
+ KeConnectInterrupt( &HalpEisaNmiInterrupt );
+
+ //
+ // Clear the Eisa NMI disable bit. This bit is the high order of the
+ // NMI enable register.
+ //
+
+ DataByte = 0;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->NmiEnable,
+ DataByte
+ );
+
+ //
+ // Enable Software-Generated NMI interrupts by setting bit 1 of port 0x461.
+ //
+
+ DataByte = 0x02;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl,
+ DataByte
+ );
+
+ //
+ // Initialize the EISA interrupt dispatcher for Jazz I/O interrupts.
+ //
+
+ KeInitializeInterrupt( &HalpEisaInterrupt,
+ HalpEisaDispatch,
+ (PVOID) EISA_INTA_CYCLE_VIRTUAL_BASE,
+ (PKSPIN_LOCK)NULL,
+ PIC_VECTOR,
+ EISA_DEVICE_LEVEL,
+ EISA_DEVICE_LEVEL,
+ LevelSensitive,
+ TRUE,
+ 0,
+ FALSE
+ );
+
+ if (!KeConnectInterrupt( &HalpEisaInterrupt )) {
+
+ return(FALSE);
+ }
+
+ //
+ // Raise the IRQL while the EISA interrupt controller is initalized.
+ //
+
+ KeRaiseIrql(EISA_DEVICE_LEVEL, &oldIrql);
+
+
+ //
+ // Initialize the 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_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
+ DataByte
+ );
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0,
+ DataByte
+ );
+
+ //
+ // The second intitialization control word sets the iterrupt vector to
+ // 0-15.
+ //
+
+ DataByte = 0;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ DataByte
+ );
+
+ DataByte = 0x08;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
+ DataByte
+ );
+
+ //
+ // The thrid initialization control word set the controls for slave mode.
+ // The master ICW3 uses bit position and the slave ICW3 uses a numberic.
+ //
+
+ DataByte = 1 << SLAVE_IRQL_LEVEL;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ DataByte
+ );
+
+ DataByte = SLAVE_IRQL_LEVEL;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->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_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ DataByte
+ );
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
+ DataByte
+ );
+
+
+ //
+ // Disable all of the interrupts except the slave.
+ //
+
+ HalpEisaInterrupt1Mask = ~(1 << SLAVE_IRQL_LEVEL);
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ HalpEisaInterrupt1Mask
+ );
+
+ HalpEisaInterrupt2Mask = 0xFF;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
+ HalpEisaInterrupt2Mask
+ );
+
+ //
+ // Initialize the edge/level register masks to 0 which is the default
+ // edge sensitive value.
+ //
+
+ HalpEisaInterrupt1Level = 0;
+ HalpEisaInterrupt2Level = 0;
+
+ //
+ // Restore IRQL level.
+ //
+
+ KeLowerIrql(oldIrql);
+
+ //
+ // Initialize the DMA mode registers to a default value.
+ // Disable all of the DMA channels except channel 4 which is the
+ // cascade of channels 0-3.
+ //
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Dma1BasePort.AllMask,
+ 0x0F
+ );
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->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;
+ PKPRCB Prcb;
+ BOOLEAN returnValue;
+ USHORT PCRInOffset;
+ UCHAR Int1Isr;
+ UCHAR Int2Isr;
+ PULONG DispatchCode;
+ PKINTERRUPT InterruptObject;
+
+ //
+ // Read the interrupt vector.
+ //
+
+ interruptVector = READ_PORT_UCHAR(ServiceContext);
+
+ //
+ // schedule the read
+ //
+
+ HalpMb();
+
+ KeStallExecutionProcessor(1);
+
+ interruptVector = READ_PORT_UCHAR(ServiceContext);
+
+
+ if ((interruptVector & 0x07) == 0x07) {
+
+ //
+ // Check for a passive release by looking at the inservice register.
+ // If there is a real IRQL7 interrupt, just go along normally. If there
+ // is not, then it is a passive release. So just dismiss it.
+ //
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
+ 0x0B
+ );
+
+ Int1Isr = READ_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0);
+
+ //
+ // do second controller
+ //
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0,
+ 0x0B
+ );
+
+ Int2Isr = READ_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0);
+
+
+ if (!(Int2Isr & 0x80) && !(Int1Isr & 0x80)) {
+
+ //
+ // Clear the master controller to clear situation
+ //
+
+ if (!(Int2Isr & 0x80)) {
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
+ NONSPECIFIC_END_OF_INTERRUPT
+ );
+
+ }
+
+ return(TRUE);
+
+ }
+
+
+ }
+
+ //
+ // Dispatch to the secondary interrupt service routine.
+ //
+ PCRInOffset = interruptVector + EISA_VECTORS;
+ DispatchCode = PCR->InterruptRoutine[PCRInOffset];
+ InterruptObject = CONTAINING_RECORD(DispatchCode,
+ KINTERRUPT,
+ DispatchCode);
+
+ returnValue = ((PSECONDARY_DISPATCH) InterruptObject->DispatchAddress)(
+ InterruptObject,
+ NULL);
+
+ //
+ // Dismiss the interrupt in the EISA interrupt controllers.
+ //
+
+ //
+ // If this is a cascaded interrupt then the interrupt must be dismissed in
+ // both controlles.
+ //
+
+ if (interruptVector & 0x08) {
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0,
+ NONSPECIFIC_END_OF_INTERRUPT
+ );
+
+ }
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
+ NONSPECIFIC_END_OF_INTERRUPT
+ );
+
+ return(returnValue);
+
+}
+
+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_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
+ HalpEisaInterrupt2Mask
+ );
+
+ } else {
+
+ //
+ // The interrupt is in controller 1.
+ //
+
+ Vector &= 0x7;
+
+ //
+ // never disable IRQL2, it is the slave interrupt
+ //
+
+ if (Vector != SLAVE_IRQL_LEVEL) {
+ HalpEisaInterrupt1Mask |= (ULONG) 1 << Vector;
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ HalpEisaInterrupt1Mask
+ );
+ }
+
+ }
+
+}
+
+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_PORT_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_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2EdgeLevel,
+ HalpEisaInterrupt2Level
+ );
+
+ } else {
+
+ //
+ // The interrupt is in controller 1.
+ //
+
+ Vector &= 0x7;
+
+ HalpEisaInterrupt1Mask &= (UCHAR) ~(1 << Vector);
+ WRITE_PORT_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_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1EdgeLevel,
+ HalpEisaInterrupt1Level
+ );
+ }
+
+}
+
+BOOLEAN
+HalHandleNMI(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext
+ )
+/*++
+
+Routine Description:
+
+ This function is called when an EISA NMI occurs. It print the appropriate
+ status information and bugchecks.
+
+Arguments:
+
+ Interrupt - Supplies a pointer to the interrupt object
+
+ ServiceContext - Bug number to call bugcheck with.
+
+Return Value:
+
+ Returns TRUE.
+
+--*/
+{
+ UCHAR StatusByte;
+ UCHAR EisaPort;
+ ULONG port;
+ ULONG AddressSpace = 1; // 1 = I/O address space
+ BOOLEAN Status;
+ PHYSICAL_ADDRESS BusAddress;
+ PHYSICAL_ADDRESS TranslatedAddress;
+
+ StatusByte =
+ READ_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->NmiStatus);
+
+ if (StatusByte & 0x80) {
+ HalDisplayString ("NMI: Parity Check / Parity Error\n");
+ }
+
+ if (StatusByte & 0x40) {
+ HalDisplayString ("NMI: Channel Check / IOCHK\n");
+ }
+
+ //
+ // This is an Eisa machine, check for extnded nmi information...
+ //
+
+ StatusByte = READ_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl);
+
+ if (StatusByte & 0x80) {
+ HalDisplayString ("NMI: Fail-safe timer\n");
+ }
+
+ if (StatusByte & 0x40) {
+ HalDisplayString ("NMI: Bus Timeout\n");
+ }
+
+ if (StatusByte & 0x20) {
+ HalDisplayString ("NMI: Software NMI generated\n");
+ }
+
+ //
+ // Look for any Eisa expansion board. See if it asserted NMI.
+ //
+
+ BusAddress.HighPart = 0;
+
+ for (EisaPort = 0; EisaPort <= 0xf; EisaPort++)
+ {
+ BusAddress.LowPart = (EisaPort << 12) + 0xC80;
+
+ Status = HalTranslateBusAddress(Eisa, // InterfaceType
+ 0, // BusNumber (0 for Jensen)
+ BusAddress,
+ &AddressSpace, // 1=I/O address space
+ &TranslatedAddress); // QVA
+ if (Status == FALSE)
+ {
+ UCHAR pbuf[80];
+ sprintf(pbuf,
+ "Unable to translate bus address %x for EISA slot %d\n",
+ BusAddress.LowPart, EisaPort);
+ HalDisplayString(pbuf);
+ KeBugCheck(NMI_HARDWARE_FAILURE);
+ }
+
+ port = TranslatedAddress.LowPart;
+
+ WRITE_PORT_UCHAR ((PUCHAR) port, 0xff);
+ StatusByte = READ_PORT_UCHAR ((PUCHAR) port);
+
+ if ((StatusByte & 0x80) == 0) {
+ //
+ // Found valid Eisa board, Check to see if it's
+ // if IOCHKERR is asserted.
+ //
+
+ StatusByte = READ_PORT_UCHAR ((PUCHAR) port+4);
+ if (StatusByte & 0x2) {
+ EisaNMIMsg[25] = (EisaPort > 9 ? 'A'-10 : '0') + EisaPort;
+ HalDisplayString (EisaNMIMsg);
+ }
+ }
+ }
+
+#if 0
+ // Reset NMI interrupts (for debugging purposes only).
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl, 0x00);
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl, 0x02);
+#endif
+
+ KeBugCheck(NMI_HARDWARE_FAILURE);
+ return(TRUE);
+}
diff --git a/private/ntos/nthals/hal0jens/alpha/axibsup.c b/private/ntos/nthals/hal0jens/alpha/axibsup.c
new file mode 100644
index 000000000..5a35ec785
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/axibsup.c
@@ -0,0 +1,1089 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ axibsup.c
+
+Abstract:
+
+ The module provides the ISA bus support for Alpha/Beta
+ (Alpha PC) systems.
+ The system uses the 82380 chip set, defined in the 386 microprocessor
+ handbook. Only PICs B and C have ISA devices attached to them.
+ There is some problem with DMA on Beta; it might not work.
+
+Author:
+
+ Jeff Havens (jhavens) 19-Jun-1991
+ Miche Baker-Harvey (miche) 13-May-1992
+
+Revision History:
+ 13-May-92 Stole file jxebsup.c and converted for Alpha/Beta
+
+--*/
+
+#include "halp.h"
+// MBH: should these files really be alpha, or should they be Beta
+#include "alphadma.h"
+#include "alphadef.h"
+#include "eisa.h"
+
+//
+// Define the context structure for use by the interrupt routine.
+//
+
+typedef BOOLEAN (*PSECONDARY_DISPATCH)(
+ PVOID InterruptRoutine
+ );
+
+//
+// Declare the interupt structure and spinlock for the intermediate ISA
+// interrupt dispachter.
+//
+
+KINTERRUPT HalpIsaInterrupt;
+
+//
+// Define save area for SIA adapter objects.
+//
+
+PADAPTER_OBJECT HalpIsaAdapter[8];
+
+//
+// Define save area for EISA interrupt mask resiters and level\edge control
+// registers.
+//
+
+UCHAR HalpIsaInterrupt1Mask;
+UCHAR HalpIsaInterrupt2Mask;
+UCHAR HalpIsaInterrupt3Mask;
+UCHAR HalpIsaInterrupt1Level;
+UCHAR HalpIsaInterrupt2Level;
+UCHAR HalpIsaInterrupt3Level;
+
+
+PADAPTER_OBJECT
+HalpAllocateIsaAdapter( // MBH: not touched
+ IN PDEVICE_DESCRIPTION DeviceDescriptor
+ )
+/*++
+
+Routine Description:
+
+ This function allocates an ISA adapter object according to the
+ specification supplied in the device description. The necessary device
+ descriptor information is saved. If there is
+ no existing adapter object for this channel then a new one is allocated.
+ The saved information in the adapter object is used to set the various DMA
+ modes when the channel is allocated or a map transfer is done.
+
+Arguments:
+
+ DeviceDescription - Supplies the description of the device which want to
+ use the DMA adapter.
+
+Return Value:
+
+ Returns a pointer to the newly created adapter object or NULL if one
+ cannot be created.
+
+--*/
+
+{
+ PADAPTER_OBJECT adapterObject;
+ PVOID adapterBaseVa;
+ ULONG channelNumber;
+ ULONG controllerNumber;
+ DMA_EXTENDED_MODE extendedMode;
+ UCHAR adapterMode;
+
+ //
+ // Channel 4 cannot be used since it is used for chaining. Return null if
+ // it is requested.
+ //
+
+ if (DeviceDescriptor->DmaChannel == 4) {
+ return(NULL);
+ }
+
+
+ //
+ // 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) &((PEISA_CONTROL) HalpEisaControlBase)->Dma1BasePort;
+
+ } else {
+
+ controllerNumber = 2;
+ adapterBaseVa = &((PEISA_CONTROL) HalpEisaControlBase)->Dma2BasePort;
+
+ }
+
+ //
+ // Determine if a new adapter object is necessary. If so then allocate it.
+ //
+
+ if (HalpEisaAdapter[DeviceDescriptor->DmaChannel] != NULL) {
+
+ adapterObject = HalpEisaAdapter[DeviceDescriptor->DmaChannel];
+
+ } else {
+
+ //
+ // Allocate an adapter object.
+ //
+
+ adapterObject = (PADAPTER_OBJECT) IopAllocateAdapter(
+ 0,
+ adapterBaseVa,
+ NULL
+ );
+
+ if (adapterObject == NULL) {
+
+ return(NULL);
+
+ }
+
+ HalpEisaAdapter[DeviceDescriptor->DmaChannel] = adapterObject;
+
+ }
+
+
+ //
+ // Setup the pointers to all the random registers.
+ //
+
+ adapterObject->ChannelNumber = channelNumber;
+
+ if (controllerNumber == 1) {
+
+ switch ((UCHAR)channelNumber) {
+
+ case 0:
+ adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel0;
+ break;
+
+ case 1:
+ adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel1;
+ break;
+
+ case 2:
+ adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel2;
+ break;
+
+ case 3:
+ adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel3;
+ break;
+ }
+
+ //
+ // Set the adapter number.
+ //
+
+ adapterObject->AdapterNumber = 1;
+
+ //
+ // Save the extended mode register address.
+ //
+
+ adapterBaseVa =
+ &((PEISA_CONTROL) HalpEisaControlBase)->Dma1ExtendedModePort;
+
+ } else {
+
+ switch (channelNumber) {
+ case 1:
+ adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel5;
+ break;
+
+ case 2:
+ adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel6;
+ break;
+
+ case 3:
+ adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel7;
+ break;
+ }
+
+ //
+ // Set the adapter number.
+ //
+
+ adapterObject->AdapterNumber = 2;
+
+ //
+ // Save the extended mode register address.
+ //
+ adapterBaseVa =
+ &((PEISA_CONTROL) HalpEisaControlBase)->Dma2ExtendedModePort;
+
+ }
+
+ //
+ // Initialzie the extended mode port.
+ //
+
+ *((PUCHAR) &extendedMode) = 0;
+ extendedMode.ChannelNumber = 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;
+ break;
+
+ case Width32Bits:
+ extendedMode.TransferSize = BY_BYTE_32_BITS;
+ break;
+
+ default:
+ ObDereferenceObject( adapterObject );
+ return(NULL);
+
+ }
+
+ WRITE_PORT_UCHAR( adapterBaseVa, *((PUCHAR) &extendedMode));
+
+ //
+ // 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_PORT_UCHAR( &dmaControl->Mode, adapterMode );
+
+ //
+ // Unmask the DMA channel.
+ //
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber)
+ );
+
+ } else {
+
+ //
+ // This request is for DMA controller 1
+ //
+
+ PDMA2_CONTROL dmaControl;
+
+ dmaControl = adapterObject->AdapterBaseVa;
+
+ WRITE_PORT_UCHAR( &dmaControl->Mode, adapterMode );
+
+ //
+ // Unmask the DMA channel.
+ //
+
+ WRITE_PORT_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);
+}
+
+BOOLEAN
+HalpCreateIsaStructures ( // MBH: not touched
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the structures necessary for ISA operations
+ and connects the intermediate interrupt dispatcher. It also initializes the
+ ISA 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;
+
+ //
+ // Initialize the EISA interrupt dispatcher for Jazz I/O interrupts.
+ //
+
+ KeInitializeInterrupt( &HalpEisaInterrupt,
+ HalpEisaDispatch,
+ (PVOID) &(DMA_CONTROL->InterruptAcknowledge.Long),
+ (PKSPIN_LOCK)NULL,
+ EISA_DEVICE_LEVEL,
+ EISA_DEVICE_LEVEL,
+ EISA_DEVICE_LEVEL,
+ LevelSensitive,
+ TRUE,
+ 0,
+ FALSE
+ );
+
+ if (!KeConnectInterrupt( &HalpEisaInterrupt )) {
+
+ return(FALSE);
+ }
+
+ //
+ // Raise the IRQL while the EISA interrupt controller is initalized.
+ //
+
+ KeRaiseIrql(EISA_DEVICE_LEVEL, &oldIrql);
+
+ //
+ // TEMP: Reset the Eisa bus, since the firmware does not do for a reboot.
+ //
+
+ DataByte = 0;
+
+ ((PNMI_EXTENDED_CONTROL) &DataByte)->BusReset = 1;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl,
+ DataByte
+ );
+
+ KeStallExecutionProcessor(3);
+
+ DataByte = 0;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl,
+ DataByte
+ );
+
+ //
+ // Initialize the 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_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
+ DataByte
+ );
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0,
+ DataByte
+ );
+
+ //
+ // The second intitialization control word sets the iterrupt vector to
+ // 0-15.
+ //
+
+ DataByte = 0;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ DataByte
+ );
+
+ DataByte = 0x08;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
+ DataByte
+ );
+
+ //
+ // The thrid initialization control word set the controls for slave mode.
+ // The master ICW3 uses bit position and the slave ICW3 uses a numberic.
+ //
+
+ DataByte = 1 << SLAVE_IRQL_LEVEL;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ DataByte
+ );
+
+ DataByte = SLAVE_IRQL_LEVEL;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->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_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ DataByte
+ );
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
+ DataByte
+ );
+
+
+ //
+ // Disable all of the interrupts except the slave.
+ //
+
+ HalpEisaInterrupt1Mask = ~(1 << SLAVE_IRQL_LEVEL);
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ HalpEisaInterrupt1Mask
+ );
+
+ HalpEisaInterrupt2Mask = 0xFF;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
+ HalpEisaInterrupt2Mask
+ );
+
+ //
+ // Initialize the edge/level register masks to 0 which is the default
+ // edge sensitive value.
+ //
+
+ HalpEisaInterrupt1Level = 0;
+ HalpEisaInterrupt2Level = 0;
+
+ //
+ // Restore IRQL level.
+ //
+
+ KeLowerIrql(oldIrql);
+
+ //
+ // Initialize the DMA mode registers to a default value.
+ //
+
+
+ return(TRUE);
+}
+
+BOOLEAN
+HalpIsaDispatch( // MBH: not touched
+ 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 ISA device interrupts. Its function is to call the second
+ level interrupt dispatch routine and acknowledge the interrupt at the ISA
+ 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;
+ PKPRCB Prcb;
+ BOOLEAN returnValue;
+
+ //
+ // Read the interrupt vector.
+ //
+
+ interruptVector = READ_PORT_UCHAR(ServiceContext);
+
+ //
+ // Get the PRCB.
+ //
+
+ Prcb = KeGetCurrentPrcb();
+
+ //
+ // Dispatch to the secondary interrupt service routine.
+ //
+
+ returnValue = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[EISA_VECTORS + interruptVector])(
+ PCR->InterruptRoutine[EISA_VECTORS + interruptVector]
+ );
+
+ //
+ // Dismiss the interrupt in the EISA interrupt controllers.
+ //
+
+ //
+ // If this is a cascaded interrupt then the interrupt must be dismissed in
+ // both controlles.
+ //
+
+ if (interruptVector & 0x08) {
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0,
+ NONSPECIFIC_END_OF_INTERRUPT
+ );
+
+ }
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
+ NONSPECIFIC_END_OF_INTERRUPT
+ );
+
+ return(returnValue);
+
+}
+
+VOID
+HalpDisableIsaInterrupt(
+ IN CCHAR Vector
+ )
+
+/*++
+
+Routine Description:
+
+ This function Disables the ISA bus specified ISA bus interrupt.
+
+Arguments:
+
+ Vector - Supplies the vector of the ISA interrupt that is Disabled.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Calculate the ISA interrupt vector.
+ //
+
+ Vector -= ISA_VECTORS;
+
+ //
+ // Determine if this vector is for interrupt controller 1 or 2 or 3.
+ //
+
+ if (Vector & 0x10) {
+
+ //
+ // The interrupt is in controller 3.
+ // Write the mask into OCW1 (same address as ICW2)
+ //
+
+ Vector &= 0x7;
+
+ HalpIsaInterrupt3Mask |= 1 << Vector;
+ WRITE_PORT_UCHAR(
+ &((PISA_CONTROL) HalpIsaControlBase)->Interrupt3ControlPort1,
+ HalpIsaInterrupt3Mask
+ );
+
+ } else if (Vector & 0x08) {
+
+ //
+ // The interrupt is in controller 2.
+ //
+
+ Vector &= 0x7;
+
+ HalpIsaInterrupt2Mask |= 1 << Vector;
+ WRITE_PORT_UCHAR(
+ &((PISA_CONTROL) HalpIsaControlBase)->Interrupt2ControlPort1,
+ HalpIsaInterrupt2Mask
+ );
+
+ } else {
+
+ //
+ // Only allowed ISA devices in banks B and C, so this is an error
+ //
+
+ HalDisplayString("Disabling ISA Interrupt in Bank A");
+// MBH: I made up this bug check number - where are they defined?
+ KeBugCheck(0x81);
+
+ }
+
+}
+
+VOID
+HalpIsaMapTransfer( // MBH: not touched
+ IN PADAPTER_OBJECT AdapterObject,
+ IN ULONG Offset,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This function programs the ISA DMA controller for a transfer.
+
+Arguments:
+
+ Adapter - Supplies the DMA adapter object to be programed.
+
+ Offset - Supplies the logical address to use for the transfer.
+
+ Length - Supplies the length of the transfer in bytes.
+
+ WriteToDevice - Indicates the direction of the transfer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PUCHAR BytePtr;
+ UCHAR adapterMode;
+
+ BytePtr = (PUCHAR) &Offset;
+
+ ASSERT((Offset >= 0x100000 && !(Length & 1)));
+
+ adapterMode = AdapterObject->AdapterMode;
+
+ //
+ // Check to see if this request is for a master I/O card.
+ //
+
+ if (((PDMA_EISA_MODE) &adapterMode)->RequestMode == CASCADE_REQUEST_MODE) {
+
+ //
+ // Set the mode, Disable the request and return.
+ //
+
+ if (AdapterObject->AdapterNumber == 1) {
+
+ //
+ // This request is for DMA controller 1
+ //
+
+ PDMA1_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_PORT_UCHAR( &dmaControl->Mode, adapterMode );
+
+ //
+ // Unmask the DMA channel.
+ //
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber)
+ );
+
+ } else {
+
+ //
+ // This request is for DMA controller 1
+ //
+
+ PDMA2_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_PORT_UCHAR( &dmaControl->Mode, adapterMode );
+
+ //
+ // Unmask the DMA channel.
+ //
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber)
+ );
+
+ }
+
+ return;
+ }
+
+
+ //
+ // Determine the mode based on the transfer direction.
+ //
+
+ ((PDMA_EISA_MODE) &adapterMode)->TransferType = WriteToDevice ?
+ WRITE_TRANSFER : READ_TRANSFER;
+
+ //
+ // Determine the controller number based on the Adapter base va.
+ //
+
+ if (AdapterObject->AdapterNumber == 1) {
+
+ //
+ // This request is for DMA controller 1
+ //
+
+ PDMA1_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 );
+
+ WRITE_PORT_UCHAR( &dmaControl->Mode, adapterMode );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseAddress,
+ BytePtr[0]
+ );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseAddress,
+ BytePtr[1]
+ );
+
+ WRITE_PORT_UCHAR(
+ ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageLowPort) +
+ (ULONG)AdapterObject->PagePort,
+ BytePtr[2]
+ );
+
+ //
+ // Write the high page register with zero value. This enable a special mode
+ // which allows ties the page register and base count into a single 24 bit
+ // address register.
+ //
+
+ WRITE_PORT_UCHAR(
+ ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort) +
+ (ULONG)AdapterObject->PagePort,
+ 0
+ );
+
+
+ //
+ // Notify DMA chip of the length to transfer.
+ //
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount,
+ (UCHAR) ((Length - 1) & 0xff)
+ );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount,
+ (UCHAR) ((Length - 1) >> 8)
+ );
+
+
+ //
+ // Set the DMA chip to read or write mode; and unmask it.
+ //
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber)
+ );
+
+ } else {
+
+ //
+ // This request is for DMA controller 1
+ //
+
+ PDMA2_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 );
+
+ WRITE_PORT_UCHAR( &dmaControl->Mode, adapterMode );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseAddress,
+ BytePtr[0]
+ );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseAddress,
+ BytePtr[1]
+ );
+
+ WRITE_PORT_UCHAR(
+ ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageLowPort) +
+ (ULONG)AdapterObject->PagePort,
+ BytePtr[2]
+ );
+
+ //
+ // Write the high page register with zero value. This enable a special mode
+ // which allows ties the page register and base count into a single 24 bit
+ // address register.
+ //
+
+ WRITE_PORT_UCHAR(
+ ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort) +
+ (ULONG)AdapterObject->PagePort,
+ 0
+ );
+
+
+ //
+ // Notify DMA chip of the length to transfer.
+ //
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount,
+ (UCHAR) ((Length - 1) & 0xff)
+ );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount,
+ (UCHAR) ((Length - 1) >> 8)
+ );
+
+
+ //
+ // Set the DMA chip to read or write mode; and unmask it.
+ //
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber)
+ );
+ }
+
+}
+
+VOID
+HalpEnableIsaInterrupt(
+ IN CCHAR Vector,
+ IN KINTERRUPT_MODE InterruptMode
+ )
+
+/*++
+
+Routine Description:
+
+ This function enables the ISA bus specified ISA bus interrupt and sets
+ the level/edge register to the requested value.
+
+Arguments:
+
+ Vector - Supplies the vector of the ISA interrupt that is enabled.
+
+ InterruptMode - Supplies the mode of the interrupt; LevelSensitive or
+ Latched.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Calculate the ISA interrupt vector.
+ //
+
+ Vector -= ISA_VECTORS;
+
+ //
+ // Determine if this vector is for interrupt controller 1, 2 or 3.
+ //
+
+ if (Vector & 0x10) {
+
+ //
+ // The interrupt is in controller 3.
+ //
+
+ Vector &= 0x7;
+
+ HalpIsaInterrupt3Mask &= ~(1 << Vector);
+ WRITE_PORT_UCHAR(
+ &((PISA_CONTROL) HalpIsaControlBase)->Interrupt3ControlPort1,
+ HalpIsaInterrupt3Mask
+ );
+
+ //
+ // Set the level/edge control register.
+ //
+
+ if (InterruptMode == LevelSensitive) {
+
+ HalpIsaInterrupt3Level |= (1 << Vector);
+
+ } else {
+
+ HalpIsaInterrupt3Level &= ~(1 << Vector);
+
+ }
+
+ if (Vector & 0x08) {
+
+ //
+ // The interrupt is in controller 2.
+ //
+
+ Vector &= 0x7;
+
+ HalpIsaInterrupt2Mask &= ~(1 << Vector);
+ WRITE_PORT_UCHAR(
+ &((PISA_CONTROL) HalpIsaControlBase)->Interrupt2ControlPort1,
+ HalpIsaInterrupt2Mask
+ );
+
+ //
+ // Set the level/edge control register.
+ //
+
+ if (InterruptMode == LevelSensitive) {
+
+ HalpIsaInterrupt2Level |= (1 << Vector);
+
+ } else {
+
+ HalpIsaInterrupt2Level &= ~(1 << Vector);
+
+ }
+
+ } else {
+
+ //
+ // Only allowed ISA devices in banks B and C, so this is an error
+ //
+
+ HalDisplayString("Enabling ISA Interrupt in Bank A");
+// MBH: I made up this bug check number - where are they defined?
+ KeBugCheck(0x82);
+
+ }
+
+}
diff --git a/private/ntos/nthals/hal0jens/alpha/axlbsup.c b/private/ntos/nthals/hal0jens/alpha/axlbsup.c
new file mode 100644
index 000000000..41566ff77
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/axlbsup.c
@@ -0,0 +1,84 @@
+/*++
+
+Copyright (c) 1992 Digital Equipment Corporation
+
+Module Name:
+
+ .../ntos/hal/alpha/axlbsup.c
+
+Abstract:
+
+
+ These routines are used to access the 82C106 on various platforms.
+ It is local for both Beta and Jensen, but Beta accesses it through
+ the Xbus while Jensen accesses it through the Hbus.
+ These routines assume that a port number and data is sufficient.
+
+ Stolen from Joe Notarangelo's hal.c in nttools
+
+Author:
+
+ Joe Notarangelo
+ Miche Baker-Harvey (miche) 18-May-1992
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+
+
+VOID
+HalpWriteVti(
+ ULONG Port,
+ UCHAR Data
+ )
+/*++
+
+Routine Description:
+
+ This function writes a byte to the specified port in the VTI 82C106
+
+Arguments:
+
+ Port - Supplies the local port number
+ Data - Byte of data to be written to the port
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+ outVti( Port, Data );
+}
+
+UCHAR
+HalpReadVti(
+ ULONG Port
+ )
+/*++
+
+Routine Description:
+
+ This function writes a byte to the specified port in the VTI 82C106.
+
+
+Arguments:
+
+ Port - Supplies the local port number
+
+
+Return Value:
+
+ Data byte read from port
+
+--*/
+{
+ return( (UCHAR)inVti( Port ) );
+}
diff --git a/private/ntos/nthals/hal0jens/alpha/axsysint.c b/private/ntos/nthals/hal0jens/alpha/axsysint.c
new file mode 100644
index 000000000..102818113
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/axsysint.c
@@ -0,0 +1,473 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ axsysint.c
+
+Abstract:
+
+ This module implements the HAL enable/disable system interrupt, and
+ request interprocessor interrupt routines for the alpha system JENSEN.
+
+Author:
+
+ David N. Cutler (davec) 6-May-1991
+ Miche Baker-Harvey (miche) 13-May-1992
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ 08-Jul-1992 Joe Notarangelo
+ Add support for performance counter interrupts.
+ Add support to enable/disable serial and keyboard interrupts via the
+ standard HalEnable/Disable interfaces.
+ NOTE: This module is now, decidely JENSEN-specific.
+
+ 28-Jul-1992 Jeff McLeman (DEC)
+ Remove reference to ISA
+
+ 13-May-92 Converted to Alpha Beta and Jensen (EV4-based)
+ systems. Stole from jxsysint.c
+ Beta is ISA/82380; Jensen is EISA/82357, as is Jazz
+
+--*/
+
+#include "halp.h"
+#include "jnsnint.h"
+#include "jnsndef.h"
+#include "axp21064.h"
+
+//
+// Define reference to the builtin device interrupt enables.
+//
+
+extern USHORT HalpBuiltinInterruptEnable;
+
+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 IrqlIndex;
+ PIETEntry_21064 IetEntry;
+ KIRQL OldIrql;
+
+ //
+ // Raise IRQL to the highest level.
+ //
+
+ KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+
+ //
+ // If the vector number is within the range of the EISA interrupts, then
+ // disable the EISA interrrupt.
+ //
+
+ if (Vector >= EISA_VECTORS &&
+ Vector < EISA_VECTORS + MAXIMUM_EISA_VECTOR &&
+ Irql == EISA_DEVICE_LEVEL) {
+ HalpDisableEisaInterrupt(Vector);
+ }
+
+ //
+ // If the vector is a performance counter vector or one of the internal
+ // device vectors (serial and keyboard/mouse for JENSEN) then disable the
+ // interrupt in the IET and alert the PAL to re-cache the interrupt
+ // enable masks.
+ //
+
+ if( (Vector == SERIAL_VECTOR) ||
+ (Vector == KEYBOARD_MOUSE_VECTOR) ||
+ (Vector == PC0_VECTOR) ||
+ (Vector == PC1_VECTOR) ){
+
+ IetEntry = (PIETEntry_21064)&PCR->IrqlTable;
+ IrqlIndex = PASSIVE_LEVEL;
+
+ //
+ // Update the enable table for all the Irqls such that the interrupt
+ // is disabled.
+ //
+
+ while( IrqlIndex <= HIGH_LEVEL ){
+
+ switch( Vector ){
+
+ case PC0_VECTOR:
+
+ IetEntry[IrqlIndex].PerformanceCounter0Enable = 0;
+ break;
+
+ case PC1_VECTOR:
+
+ IetEntry[IrqlIndex].PerformanceCounter1Enable = 0;
+ break;
+
+ case SERIAL_VECTOR:
+
+ IetEntry[IrqlIndex].Irq5Enable = 0;
+ break;
+
+ case KEYBOARD_MOUSE_VECTOR:
+
+ IetEntry[IrqlIndex].Irq3Enable = 0;
+ break;
+
+ } //end switch( Vector )
+
+ IrqlIndex++;
+
+ } //end while IrqlIndex <= HIGH_LEVEL
+
+ //
+ // Alert the PAL that the enable table has changed so that it can
+ // reload the new values.
+ //
+
+ HalpCachePcrValues();
+
+ } //end if Vector == SERIAL_VECTOR, etc.
+
+ //
+ // Lower IRQL to the previous level.
+ //
+
+ 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 IrqlIndex;
+ PIETEntry_21064 IetEntry;
+ KIRQL OldIrql;
+
+ //
+ // Raise IRQL to the highest level.
+ //
+
+ KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+
+ //
+ // If the vector number is within the range of the EISA interrupts, then
+ // enable the EISA interrrupt and set the Level/Edge register.
+ //
+
+ if (Vector >= EISA_VECTORS &&
+ Vector < EISA_VECTORS + MAXIMUM_EISA_VECTOR &&
+ Irql == EISA_DEVICE_LEVEL) {
+ HalpEnableEisaInterrupt( Vector, InterruptMode);
+ }
+
+ //
+ // If the vector is a performance counter vector or one of the
+ // internal device vectors (serial or keyboard/mouse) then enable the
+ // interrupt in the IET and alert the PAL to re-cache the interrupt
+ // enable masks.
+ //
+
+ if( (Vector == SERIAL_VECTOR) ||
+ (Vector == KEYBOARD_MOUSE_VECTOR) ||
+ (Vector == PC0_VECTOR) ||
+ (Vector == PC1_VECTOR) ){
+
+ IetEntry = (PIETEntry_21064)&PCR->IrqlTable;
+ IrqlIndex = PASSIVE_LEVEL;
+
+ //
+ // Update the enable table for each Irql that the interrupt should
+ // be enabled.
+ //
+
+ while( IrqlIndex < Irql ){
+
+ switch( Vector ){
+
+ case PC0_VECTOR:
+
+ IetEntry[IrqlIndex].PerformanceCounter0Enable = 1;
+ break;
+
+ case PC1_VECTOR:
+
+ IetEntry[IrqlIndex].PerformanceCounter1Enable = 1;
+ break;
+
+ case SERIAL_VECTOR:
+
+ IetEntry[IrqlIndex].Irq5Enable = 1;
+ break;
+
+ case KEYBOARD_MOUSE_VECTOR:
+
+ IetEntry[IrqlIndex].Irq3Enable = 1;
+ break;
+
+ } // end switch( Vector )
+
+ IrqlIndex++;
+
+ } //end while IrqlIndex < Irql
+
+ //
+ // Alert the PAL that the enable table has changed so that it can
+ // reload the new values.
+ //
+
+ HalpCachePcrValues();
+
+ } //end if Vector == SERIAL_VECTOR, etc.
+
+ //
+ // Lower IRQL to the previous level.
+ //
+
+ KeLowerIrql(OldIrql);
+ return TRUE;
+}
+
+ULONG
+HalpGetSystemInterruptVector(
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN ULONG BusInterruptLevel,
+ IN ULONG BusInterruptVector,
+ OUT PKIRQL Irql,
+ OUT PKAFFINITY Affinity
+ )
+
+/*++
+
+Routine Description:
+
+ 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.
+
+ We only use InterfaceType, and BusInterruptLevel. BusInterruptVector
+ for ISA and EISA are the same as the InterruptLevel, so ignore.
+
+Arguments:
+
+ BusHandler - Registered BUSHANDLER for the target configuration space
+
+ RootHandler - Registered BUSHANDLER for the orginating HalGetBusData
+ request.
+
+ 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.
+
+--*/
+
+{
+ INTERFACE_TYPE InterfaceType = BusHandler->InterfaceType;
+ ULONG BusNumber = BusHandler->BusNumber;
+
+ *Affinity = 1;
+
+ //
+ // Handle the special internal bus defined for the processor itself
+ // and used to control the performance counters in the 21064.
+ //
+
+ if(InterfaceType == ProcessorInternal) {
+
+ *Irql = IPI_LEVEL;
+
+ switch( BusInterruptLevel ){
+
+ //
+ // Performance Counter 0
+ //
+
+ case 0:
+
+ return PC0_VECTOR;
+
+ //
+ // Performance Counter 1
+ //
+
+ case 1:
+
+ return PC1_VECTOR;
+
+ //
+ // Unrecognized.
+ //
+
+ default:
+
+ *Irql = 0;
+ *Affinity = 0;
+ return 0;
+
+ } //end switch( BusInterruptLevel )
+
+ } // end if InterfaceType == ProcessorInternal
+
+ //
+ // If this is for the internal bus then everything but the serial
+ // lines comes in on DEVICE_LOW, and the vector depends on the
+ // particular device. We have coded things like "SERIAL_VECTOR"
+ // into the drivers for the built-in devices.
+ //
+
+ if (InterfaceType == Internal) {
+
+ if (BusInterruptVector == SERIAL_VECTOR) {
+
+ //
+ // This is the only device which interrupts at DEVICE_HIGH_LEVEL
+ //
+
+ *Irql = DEVICE_HIGH_LEVEL;
+
+ } else {
+
+ *Irql = DEVICE_LOW_LEVEL;
+
+ }
+
+ return(BusInterruptVector);
+ }
+
+ if (InterfaceType == Isa) {
+
+ //
+ // Assumes all ISA devices coming in on same pin
+ //
+
+ *Irql = ISA_DEVICE_LEVEL;
+
+ //
+ // The vector is equal to the specified bus level plus the ISA_VECTOR.
+ // This is assuming that the ISA levels not assigned Interrupt Levels
+ // in the Beta programming guide are unused in the Jensen system.
+ // Otherwise, need a different encoding scheme.
+ //
+ // Not all interrupt levels are actually supported on Beta;
+ // Should we make some of them illegal here?
+
+ return(BusInterruptLevel + ISA_VECTORS);
+
+ }
+
+ if (InterfaceType == Eisa) {
+
+ //
+ // Assumes all EISA devices coming in on same pin
+ //
+
+ *Irql = EISA_DEVICE_LEVEL;
+
+ //
+ // The vector is equal to the specified bus level plus the EISA_VECTOR.
+ //
+
+ return(BusInterruptLevel + EISA_VECTORS);
+
+ }
+
+ //
+ // Not an interface supported on Alpha systems
+ //
+
+ *Irql = 0;
+ *Affinity = 0;
+ return(0);
+
+}
+
+VOID
+HalRequestIpi (
+ IN ULONG Mask
+ )
+
+/*++
+
+Routine Description:
+
+ This routine requests an interprocessor interrupt on a set of processors.
+
+ For all currently known machines - there's only one processor
+
+Arguments:
+
+ Mask - Supplies the set of processors that are sent an interprocessor
+ interrupt.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ return;
+}
diff --git a/private/ntos/nthals/hal0jens/alpha/bios.c b/private/ntos/nthals/hal0jens/alpha/bios.c
new file mode 100644
index 000000000..52b5dc898
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/bios.c
@@ -0,0 +1,105 @@
+/*++
+
+Copyright (c) 1993 Digital Equipment Corporation
+
+Module Name:
+
+ bios.c
+
+Abstract:
+
+ This module implements ROM BIOS call support for Alpha AXP NT.
+
+Author:
+
+ Eric Rehm (rehm@zso.dec.com) 9-December-1993
+
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "arccodes.h"
+#include "alpharef.h"
+#include "fwcallbk.h"
+
+
+//
+// Static data.
+//
+// none.
+
+
+BOOLEAN
+HalCallBios (
+ IN ULONG BiosCommand,
+ IN OUT PULONG pEax,
+ IN OUT PULONG pEbx,
+ IN OUT PULONG pEcx,
+ IN OUT PULONG pEdx,
+ IN OUT PULONG pEsi,
+ IN OUT PULONG pEdi,
+ IN OUT PULONG pEbp
+ )
+
+/*++
+
+Routine Description:
+
+ This function invokes specified ROM BIOS code by executing
+ "INT BiosCommand." A callback to the i386 emulator loaded by
+ the firmware accomplishes this task. This function always
+ returns success reguardless of the result of the BIOS call.
+
+
+Arguments:
+
+ BiosCommand - specifies which ROM BIOS function to invoke.
+
+ BiosArguments - specifies a pointer to the context which will be used
+ to invoke ROM BIOS.
+
+Return Value:
+
+ TRUE if function succees, FALSE otherwise.
+
+--*/
+{
+
+ X86_BIOS_ARGUMENTS context;
+
+ context.Edi = *pEdi;
+ context.Esi = *pEsi;
+ context.Eax = *pEax;
+ context.Ebx = *pEbx;
+ context.Ecx = *pEcx;
+ context.Edx = *pEdx;
+ context.Ebp = *pEbp;
+
+ //
+ // Now call the firmware to actually perform the int 10 operation.
+ //
+
+ VenCallBios(BiosCommand, &context);
+
+ //
+ // fill in struct with any return values from the context
+ //
+
+ *pEdi = context.Edi;
+ *pEsi = context.Esi;
+ *pEax = context.Eax;
+ *pEbx = context.Ebx;
+ *pEcx = context.Ecx;
+ *pEdx = context.Edx;
+ *pEbp = context.Ebp;
+
+
+ //
+ // Indicate success
+ //
+
+ return TRUE;
+}
+
diff --git a/private/ntos/nthals/hal0jens/alpha/ev4ints.s b/private/ntos/nthals/hal0jens/alpha/ev4ints.s
new file mode 100644
index 000000000..6df823ab6
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/ev4ints.s
@@ -0,0 +1,6 @@
+//
+// This file simply includes the source file from the common Alpha
+// HAL directory.
+//
+#include "..\halalpha\ev4ints.s"
+
diff --git a/private/ntos/nthals/hal0jens/alpha/ev4prof.c b/private/ntos/nthals/hal0jens/alpha/ev4prof.c
new file mode 100644
index 000000000..7ecdfa8b7
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/ev4prof.c
@@ -0,0 +1,7 @@
+//
+// This file simply includes the source file from the common Alpha
+// HAL directory.
+//
+
+#include "..\halalpha\ev4prof.c"
+
diff --git a/private/ntos/nthals/hal0jens/alpha/halp.h b/private/ntos/nthals/hal0jens/alpha/halp.h
new file mode 100644
index 000000000..25d7a66c0
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/halp.h
@@ -0,0 +1,223 @@
+/*++ BUILD Version: 0003 // Increment this if a change has global effects
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1992 Digital Equipment Corporation
+
+Module Name:
+
+ halp.h
+
+Abstract:
+
+ This header file defines the private Hardware Architecture Layer (HAL)
+ interfaces.
+
+Author:
+
+ David N. Cutler (davec) 25-Apr-1991
+ Miche Baker-Harvey (miche) 22-Apr-1992
+
+
+Revision History:
+
+ 09-Jul-1992 Jeff McLeman (mcleman)
+ If processor is an Alpha, include XXHALP.C for Alpha.
+
+--*/
+
+#ifndef _HALP_
+#define _HALP_
+#include "nthal.h"
+#include "hal.h"
+
+//
+// Define function prototypes.
+//
+
+BOOLEAN
+HalpCalibrateStall (
+ VOID
+ );
+
+VOID
+HalpClockInterrupt (
+ VOID
+ );
+
+VOID
+HalpPerformanceCounter0Interrupt (
+ VOID
+ );
+
+VOID
+HalpPerformanceCounter1Interrupt (
+ VOID
+ );
+
+BOOLEAN
+HalpCreateDmaStructures (
+ VOID
+ );
+
+BOOLEAN
+HalpDmaDispatch(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext
+ );
+
+BOOLEAN
+HalpInitializeDisplay (
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ );
+
+BOOLEAN
+HalpInitializeInterrupts (
+ VOID
+ );
+
+VOID
+HalpInitializeProcessorParameters(
+ VOID
+ );
+
+VOID
+HalpInitializeProfiler(
+ VOID
+ );
+
+BOOLEAN
+HalpMapFixedTbEntries (
+ VOID
+ );
+
+BOOLEAN
+HalpMapIoSpace (
+ VOID
+ );
+
+PVOID
+HalpMapPhysicalMemory(
+ IN PVOID PhysicalAddress,
+ IN ULONG NumberOfPages
+ );
+
+PVOID
+HalpRemapVirtualAddress(
+ IN PVOID VirtualAddress,
+ IN PVOID PhysicalAddress
+ );
+
+ULONG
+HalpAllocPhysicalMemory(
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock,
+ IN ULONG MaxPhysicalAddress,
+ IN ULONG NumberOfPages,
+ IN BOOLEAN bAlignOn64k
+ );
+
+VOID
+HalpProgramIntervalTimer(
+ IN ULONG RateSelect
+ );
+
+VOID
+HalpStallInterrupt (
+ VOID
+ );
+
+VOID
+HalpVideoReboot(
+ VOID
+ );
+
+//
+// Define Bus Handler support function prototypes.
+//
+
+
+VOID
+HalpRegisterInternalBusHandlers (
+ VOID
+ );
+
+ULONG
+HalpGetSystemInterruptVector(
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN ULONG BusInterruptLevel,
+ IN ULONG BusInterruptVector,
+ OUT PKIRQL Irql,
+ OUT PKAFFINITY Affinity
+ );
+
+BOOLEAN
+HalpTranslateSystemBusAddress(
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN PHYSICAL_ADDRESS BusAddress,
+ IN OUT PULONG AddressSpace,
+ OUT PPHYSICAL_ADDRESS TranslatedAddress
+ );
+
+NTSTATUS
+HalpAdjustEisaResourceList (
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList
+ );
+
+NTSTATUS
+HalpAdjustIsaResourceList (
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList
+ );
+
+
+#if defined(JENSEN)
+
+#include "jxhalp.h"
+
+#endif
+
+#if defined(FLAMINGO)
+
+#include "fxhalp.h"
+
+#endif
+
+//
+// Include alpha processor interfaces
+//
+
+#include "xxhalp.h"
+
+//
+// Define external references.
+//
+
+extern ULONG HalpCurrentTimeIncrement;
+extern ULONG HalpNextRateSelect;
+extern ULONG HalpNextTimeIncrement;
+extern ULONG HalpNewTimeIncrement;
+
+extern ULONG HalpClockFrequency;
+extern ULONG HalpClockMegaHertz;
+
+extern ULONG HalpProfileCountRate;
+
+extern PADAPTER_OBJECT MasterAdapterObject;
+
+extern BOOLEAN LessThan16Mb;
+
+//
+// Map buffer prameters. These are initialized in HalInitSystem
+//
+
+extern PHYSICAL_ADDRESS HalpMapBufferPhysicalAddress;
+extern ULONG HalpMapBufferSize;
+
+extern ULONG HalpBusType;
+extern ULONG HalpCpuType;
+
+#endif // _HALP_
diff --git a/private/ntos/nthals/hal0jens/alpha/halpal.s b/private/ntos/nthals/hal0jens/alpha/halpal.s
new file mode 100644
index 000000000..1a0ea3a36
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/halpal.s
@@ -0,0 +1,184 @@
+// TITLE("Alpha PAL funtions for HAL")
+//++
+//
+// Copyright (c) 1992-1993 Digital Equipment Corporation
+//
+// Module Name:
+//
+// palhalt.s
+//
+// Abstract:
+//
+// This module implements routines to call PAL functions
+// from the Hal.
+//
+//
+// Author:
+//
+// Jeff McLeman (mcleman) 09-Jul-1992
+//
+// Environment:
+//
+// Kernel mode only.
+//
+// Revision History:
+//
+// 13-Jul-1992 Jeff McLeman (mcleman)
+// add HalpMb to functions.
+//
+// 14-Dec-1993 Joe Notarangelo
+// Change HalpHalt to HalpReboot to fit new call pal encodings.
+//--
+
+#include "ksalpha.h"
+
+//++
+//
+// VOID
+// HalpReboot(
+// )
+//
+// Routine Description:
+//
+// This function merely calls the PAL to reboot the Alpha processor.
+// THis is used to restart the console firmware. (Note, MIPS does
+// not have a REBOOT instruction, so there had to be a mechanism to
+// restart the firware. Alpha merely reboots, which causes a jump
+// to firmware PAL, which restarts the firmware.)
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalpReboot)
+
+ REBOOT // call the PAL to reboot to firmware
+
+ .end HalpReboot
+
+//++
+//
+// VOID
+// HalpImb(
+// )
+//
+// Routine Description:
+//
+// This function merely calls the PAL to issue an Instruction
+// Memory Barrier on the Alpha processor..
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalpImb)
+
+ IMB // call the PAL to do an IMB
+
+ ret zero,(ra)
+
+ .end HalpImb
+
+
+//++
+//
+// VOID
+// HalpMb(
+// )
+//
+// Routine Description:
+//
+// This function merely calls the PAL to issue a general
+// Memory Barrier on the Alpha processor..
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalpMb)
+
+ mb // memory barrier
+
+ ret zero, (ra)
+
+ .end HalpMb
+
+//++
+//
+// VOID
+// HalpCachePcrValues(
+// )
+//
+// Routine Description:
+//
+// This function merely calls the PAL to cache values in the
+// PCR for faster access.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalpCachePcrValues)
+
+ CACHE_PCR_VALUES // call the palcode
+
+ ret zero,(ra)
+
+ .end HalpCachePcrValues
+//++
+//
+// ULONG
+// HalpRpcc(
+// )
+//
+// Routine Description:
+//
+// This function executes the RPCC (read processor cycle counter)
+// instruction.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// The low-order 32 bits of the processor cycle counter is returned
+// as the function value.
+// N.B. At 125 MHz this counter wraps about every 30 seconds. It is
+// the caller's responsibility to deal with overflow or wraparound.
+//
+//--
+
+ LEAF_ENTRY(HalpRpcc)
+
+ rpcc v0 // get rpcc value
+ addl v0, zero, v0 // extend
+
+ ret zero, (ra) // return
+
+ .end HalpRpcc
+
diff --git a/private/ntos/nthals/hal0jens/alpha/halvga.h b/private/ntos/nthals/hal0jens/alpha/halvga.h
new file mode 100644
index 000000000..c1727bd4a
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/halvga.h
@@ -0,0 +1,72 @@
+/*
+
+Copyright (c) 1992, 1993 Digital Equipment Corporation
+
+Module Name:
+
+ halvga.h
+
+
+Abstract:
+
+ Defines registers for standard VGA alphanumeric color mode video.
+ (graphics, bw mode are not defined.)
+
+ Addresses are based on the VGA video ISA base address.
+
+
+Author:
+
+ John DeRosa 4/30/92
+
+
+Revision History:
+
+ 17-Feb-1994 Eric Rehm
+ Remove all references to VGA. HAL display routines are
+ now device-independent.
+
+*/
+
+#ifndef _HALVGA_
+#define _HALVGA_
+
+//
+// Define special character values for device-indpendent control functions.
+//
+
+#define ASCII_NUL 0x00
+#define ASCII_BEL 0x07
+#define ASCII_BS 0x08
+#define ASCII_HT 0x09
+#define ASCII_LF 0x0A
+#define ASCII_VT 0x0B
+#define ASCII_FF 0x0C
+#define ASCII_CR 0x0D
+#define ASCII_CSI 0x9B
+#define ASCII_ESC 0x1B
+#define ASCII_SYSRQ 0x80
+
+//
+// Define colors, HI = High Intensity
+//
+//
+
+#define FW_COLOR_BLACK 0x00
+#define FW_COLOR_RED 0x01
+#define FW_COLOR_GREEN 0x02
+#define FW_COLOR_YELLOW 0x03
+#define FW_COLOR_BLUE 0x04
+#define FW_COLOR_MAGENTA 0x05
+#define FW_COLOR_CYAN 0x06
+#define FW_COLOR_WHITE 0x07
+#define FW_COLOR_HI_BLACK 0x08
+#define FW_COLOR_HI_RED 0x09
+#define FW_COLOR_HI_GREEN 0x0A
+#define FW_COLOR_HI_YELLOW 0x0B
+#define FW_COLOR_HI_BLUE 0x0C
+#define FW_COLOR_HI_MAGENTA 0x0D
+#define FW_COLOR_HI_CYAN 0x0E
+#define FW_COLOR_HI_WHITE 0x0F
+
+#endif // _HALVGA_
diff --git a/private/ntos/nthals/hal0jens/alpha/idle.s b/private/ntos/nthals/hal0jens/alpha/idle.s
new file mode 100644
index 000000000..0d53d7aed
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/idle.s
@@ -0,0 +1,62 @@
+// TITLE("Processor Idle Support")
+//++
+//
+// Copyright (c) 1992 Digital Equipment Corporation
+// Copyright (c) 1993 Digital Equipment Corporation
+//
+// Module Name:
+//
+// idle.s
+//
+// Abstract:
+//
+// This module implements the HalProcessorIdle interface
+//
+// Author:
+//
+// John Vert (jvert) 11-May-1994
+//
+// Environment:
+//
+// Revision History:
+//
+//--
+#include "halalpha.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 interrupts disabled. This routine
+// must do any power management enabling necessary, enable interrupts,
+// then either return or wait for an interrupt.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalProcessorIdle)
+
+ ENABLE_INTERRUPTS // no power management, just
+ // enable interrupts and return
+ ret zero, (ra)
+
+ .end HalProcessorIdle
diff --git a/private/ntos/nthals/hal0jens/alpha/jenfonts.h b/private/ntos/nthals/hal0jens/alpha/jenfonts.h
new file mode 100644
index 000000000..3a4113621
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/jenfonts.h
@@ -0,0 +1,231 @@
+/*
+
+Module Name:
+
+ jenfonts.h
+
+Abstract:
+
+ 8x16 pixel fonts for the VGA video boot driver. Stolen from
+ David Conroy's Beta-machine fonts.
+
+
+
+Author:
+
+ John DeRosa 5/7/1992
+
+
+
+Revision History:
+
+ Jeff McLeman (DEC) 28-Jul-1992
+ Stole from FW to use with HAL and renamed to header file
+
+*/
+
+
+/*
+ * ASCII characters 0x20 -- 0x7f (space -- del). Each byte is one
+ * scan line, and each character is 2 rows.
+ */
+
+unsigned char vga8x16undef[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
+
+unsigned char vga8x16chars[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0xFF, 0xFF, 0x66, 0x66,
+ 0xFF, 0xFF, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x3E, 0x7E, 0x60, 0x60, 0x7C, 0x3E,
+ 0x06, 0x06, 0x7E, 0x7C, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x6C, 0x0C, 0x18, 0x18,
+ 0x30, 0x36, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x38, 0x7C, 0x6C, 0x6C, 0x38, 0x38, 0x70, 0x70,
+ 0xDE, 0xDE, 0xCC, 0xCC, 0xFE, 0x76, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x0C, 0x1C, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x1C, 0x0C, 0x06, 0x00, 0x00,
+ 0x00, 0x00, 0x60, 0x30, 0x38, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x38, 0x30, 0x60, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x3C, 0x3C, 0xFF, 0xFF,
+ 0x3C, 0x3C, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x7E, 0x7E,
+ 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x30, 0x20,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x06, 0x06, 0x0C, 0x0C, 0x18,
+ 0x18, 0x30, 0x30, 0x60, 0x60, 0x60, 0x00, 0x00,
+ 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x6E,
+ 0x76, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x38, 0x38, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00,
+ 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x0C, 0x0C,
+ 0x18, 0x18, 0x30, 0x30, 0x7E, 0x7E, 0x00, 0x00,
+ 0x00, 0x00, 0x7E, 0x7E, 0x0C, 0x0C, 0x18, 0x18,
+ 0x0C, 0x0C, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x0C, 0x0C, 0x1C, 0x1C, 0x3C, 0x3C,
+ 0x6C, 0x6C, 0x7E, 0x7E, 0x0C, 0x0C, 0x00, 0x00,
+ 0x00, 0x00, 0x7E, 0x7E, 0x60, 0x60, 0x7C, 0x7E,
+ 0x06, 0x06, 0x06, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x1C, 0x3C, 0x70, 0x60, 0x60, 0x7C,
+ 0x7E, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x7E, 0x7E, 0x06, 0x06, 0x0C, 0x0C,
+ 0x18, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x3C, 0x3C,
+ 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x7E, 0x3E,
+ 0x06, 0x06, 0x06, 0x0E, 0x3C, 0x38, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x30, 0x20,
+ 0x00, 0x00, 0x00, 0x0E, 0x1C, 0x38, 0x70, 0xE0,
+ 0x70, 0x38, 0x1C, 0x0E, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x00, 0x00,
+ 0x7E, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xE0, 0x70, 0x38, 0x1C, 0x0E,
+ 0x1C, 0x38, 0x70, 0xE0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x0C, 0x0C,
+ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x7C, 0xE6, 0xC2, 0xDA, 0xD6,
+ 0xD6, 0xDC, 0xC0, 0xE2, 0x7E, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x66, 0x66, 0x66,
+ 0x7E, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x7E, 0x66, 0x66, 0x7E, 0x7C,
+ 0x66, 0x66, 0x66, 0x66, 0x7E, 0x7C, 0x00, 0x00,
+ 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x60, 0x60,
+ 0x60, 0x60, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x7C, 0x6E, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x6E, 0x7C, 0x78, 0x00, 0x00,
+ 0x00, 0x00, 0x7E, 0x7E, 0x60, 0x60, 0x7C, 0x7C,
+ 0x60, 0x60, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00,
+ 0x00, 0x00, 0x7E, 0x7E, 0x60, 0x60, 0x7C, 0x7C,
+ 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00,
+ 0x00, 0x00, 0x3E, 0x7E, 0x60, 0x60, 0x6E, 0x6E,
+ 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x7E,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00,
+ 0x00, 0x00, 0x7E, 0x7E, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x06, 0x06, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0xCC, 0xCC, 0xD8, 0xD8, 0xF0, 0xF0,
+ 0xD8, 0xD8, 0xCC, 0xCC, 0xC6, 0xC6, 0x00, 0x00,
+ 0x00, 0x00, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
+ 0x60, 0x60, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00,
+ 0x00, 0x00, 0xC6, 0xC6, 0xEE, 0xEE, 0xFE, 0xD6,
+ 0xD6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x76, 0x76, 0x7E,
+ 0x7E, 0x6E, 0x6E, 0x66, 0x66, 0x66, 0x00, 0x00,
+ 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x7E, 0x66, 0x66, 0x66, 0x66,
+ 0x7E, 0x7C, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00,
+ 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x6A, 0x7C, 0x36, 0x00, 0x00,
+ 0x00, 0x00, 0xF8, 0xFC, 0xCC, 0xCC, 0xCC, 0xFC,
+ 0xF8, 0xD8, 0xCC, 0xCC, 0xC6, 0xC6, 0x00, 0x00,
+ 0x00, 0x00, 0x3E, 0x7E, 0x60, 0x60, 0x70, 0x38,
+ 0x1C, 0x0E, 0x06, 0x06, 0x7E, 0x7C, 0x00, 0x00,
+ 0x00, 0x00, 0x7E, 0x7E, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6,
+ 0xD6, 0xFE, 0xFE, 0xEE, 0xC6, 0x82, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x3C, 0x18,
+ 0x18, 0x3C, 0x3C, 0x66, 0x66, 0x66, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x3C,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x7E, 0x7E, 0x0C, 0x0C, 0x18, 0x18,
+ 0x30, 0x30, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00,
+ 0x00, 0x00, 0x1E, 0x1E, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x1E, 0x1E, 0x00, 0x00,
+ 0x00, 0x00, 0x60, 0x60, 0x60, 0x30, 0x30, 0x18,
+ 0x18, 0x0C, 0x0C, 0x06, 0x06, 0x06, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x78, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x78, 0x78, 0x00, 0x00,
+ 0x00, 0x10, 0x10, 0x38, 0x38, 0x6C, 0x6C, 0xC6,
+ 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00,
+ 0x40, 0x60, 0x70, 0x38, 0x1C, 0x0C, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x3E, 0x06,
+ 0x3E, 0x7E, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x60, 0x60, 0x60, 0x7C, 0x7E, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x7E, 0x7C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x7E, 0x60,
+ 0x60, 0x60, 0x60, 0x60, 0x7E, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x06, 0x06, 0x3E, 0x7E, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x66,
+ 0x66, 0x7E, 0x60, 0x60, 0x7E, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x0E, 0x1E, 0x18, 0x18, 0x7E, 0x7E,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x7E, 0x66,
+ 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x06, 0x7E, 0x7C,
+ 0x00, 0x00, 0x60, 0x60, 0x60, 0x7C, 0x7E, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x38, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x3C, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x7C, 0x78,
+ 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xCC, 0xDC, 0xF8,
+ 0xF0, 0xF8, 0xD8, 0xCC, 0xCE, 0xC6, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x38, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x3C, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0xFE, 0xFE,
+ 0xD6, 0xD6, 0xD6, 0xC6, 0xC6, 0xC6, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x7E, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x7E, 0x7C, 0x60, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x7E, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x06, 0x06,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x7E, 0x66,
+ 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x7E, 0x60,
+ 0x70, 0x3C, 0x0E, 0x06, 0x7E, 0x7C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x7E, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x1E, 0x0E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xD6,
+ 0xD6, 0xFE, 0xFE, 0xEE, 0xC6, 0x82, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x3C,
+ 0x3C, 0x18, 0x3C, 0x3C, 0x66, 0x66, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x06, 0x7E, 0x7C,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x0C,
+ 0x18, 0x18, 0x30, 0x30, 0x7E, 0x7E, 0x00, 0x00,
+ 0x00, 0x0E, 0x18, 0x18, 0x18, 0x18, 0x38, 0xF0,
+ 0xF0, 0x38, 0x18, 0x18, 0x18, 0x18, 0x0E, 0x00,
+ 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x00, 0xE0, 0x30, 0x30, 0x30, 0x30, 0x38, 0x1E,
+ 0x1E, 0x38, 0x30, 0x30, 0x30, 0x30, 0xE0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0xF2, 0xBE,
+ 0x9C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
diff --git a/private/ntos/nthals/hal0jens/alpha/jxbeep.c b/private/ntos/nthals/hal0jens/alpha/jxbeep.c
new file mode 100644
index 000000000..633f75ac0
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/jxbeep.c
@@ -0,0 +1,133 @@
+#if defined(JENSEN)
+
+/*++
+
+Copyright (c) 1992 Digital Equipment Corporation
+
+Module Name:
+
+ jxbeep.c
+
+Abstract:
+
+ This module implements the HAL speaker "beep" routines for the
+ Alpha/Jensen system.
+
+Author:
+
+ Jeff McLeman (mcleman) 23-Jun-1992
+
+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;
+ TIMER_CONTROL timerControl;
+ ULONG newCount;
+
+ controlBase = HalpEisaControlBase;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
+
+ //
+ // Stop the speaker.
+ //
+
+ *((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus);
+
+ NmiStatus.SpeakerGate = 0;
+ NmiStatus.SpeakerData = 0;
+
+ WRITE_PORT_UCHAR(&controlBase->NmiStatus, *((PUCHAR) &NmiStatus));
+
+ if (Frequency == 0) {
+ KeLowerIrql(oldIrql);
+ return(TRUE);
+ }
+
+ //
+ // Calculate the new counter value.
+ //
+
+ newCount = TIMER_CLOCK_IN / Frequency;
+
+ //
+ // The new count must be less than 16 bits in value.
+ //
+
+ if (newCount >= 0x10000) {
+ KeLowerIrql(oldIrql);
+ return(FALSE);
+ }
+
+ //
+ // 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_PORT_UCHAR(&controlBase->CommandMode1, *((PUCHAR) &timerControl));
+
+ //
+ // Set the speaker timer to the correct mode.
+ //
+
+ WRITE_PORT_UCHAR(&controlBase->SpeakerTone, newCount);
+ WRITE_PORT_UCHAR(&controlBase->SpeakerTone, (newCount >> 8));
+
+ //
+ // Start the speaker.
+ //
+
+ NmiStatus.SpeakerGate = 1;
+ NmiStatus.SpeakerData = 1;
+
+ WRITE_PORT_UCHAR(&controlBase->NmiStatus, *((PUCHAR) &NmiStatus));
+
+ KeLowerIrql(oldIrql);
+
+ return(TRUE);
+
+}
+
+#endif
diff --git a/private/ntos/nthals/hal0jens/alpha/jxcache.c b/private/ntos/nthals/hal0jens/alpha/jxcache.c
new file mode 100644
index 000000000..cde92dab0
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/jxcache.c
@@ -0,0 +1,521 @@
+/*++
+
+Copyright (c) 1992 Digital Equipment Corporation
+
+Module Name:
+
+ jxcache.c
+
+Abstract:
+
+ This file contains the routines for managing the caches on Jensen.
+
+ Jensen is based on EV4, which has primary I and D caches, both
+ write-through. Jensen has a single back-up cache. This cache is
+ write-back, but it is also coherent with all DMA operations. The
+ primary caches are shadowed by the backup, and on a write hit, the
+ primary data (but not instruction) cache is invalidated.
+ Consequently, the routines to flush,sweep,purge,etc the data
+ stream are nops on Jensen, but the corresponding routines for the
+ Istream must ensure that we cannot hit in the primary I cache
+ after a DMA operation.
+
+ Jensen has a write buffer which contains 4 32-byte entries, which
+ must be flushable before DMA operations. The MB instruction is
+ used to accomplish this.
+
+ There is no coloring support on Jensen, so Color operations are
+ null. Zero page is unsupported because it has no users. Copy
+ page is not special because we lack coloring.
+
+ We had to make a philosophical decision about what interfaces to
+ support in this file. (Almost) none of the interfaces defined in
+ the HAL spec are actually supported in either the i386 or MIPS
+ code. The i386 stream has almost no cache support at all. The
+ Mips stream has cache support, but most routines also refer to
+ coloring. Should we use the Spec'ed interfaces, or the Mips
+ interfaces? I have elected the Mips interfaces because they are
+ in use, and we are stealing much of the Mips code which expects
+ these interfaces. Besides, the only change we might make is to
+ remove the coloring arguments, but they may be used on Alpha
+ machines at some future date.
+
+Author:
+
+ Miche Baker-Harvey (miche) 29-May-1992
+
+Revision History:
+
+
+ 13-Jul-1992 Jeff McLeman (mcleman)
+ use HalpMb to do a memory barrier. Also, alter code and use super
+ pages to pass to rtl memory routines.
+
+ 10-Jul-1992 Jeff McLeman (mcleman)
+ use HalpImb to call pal.
+
+ 06-Jul-1992 Jeff McLeman (mcleman)
+ Move routine KeFlushDcache into this module.
+ Use only one memory barrier in the KeFlushWriteBuffer
+ routine. This is because the PAL for the EVx will
+ make sure the proper write ordering is done in PAL mode.
+
+--*/
+ // Include files
+
+#include "halp.h"
+
+
+
+VOID
+HalFlushDcache (
+ IN BOOLEAN AllProcessors
+ );
+
+//
+// Cache and write buffer flush functions.
+//
+
+
+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. Jensen machines do not have page coloring, and
+ therefore, this function performs no operation.
+
+Arguments:
+
+ NewColor - Supplies the page aligned virtual address of the
+ new color of the page to change.
+
+ OldColor - Supplies the page aligned virtual address of the
+ old color of the page to change.
+
+ pageFrame - Supplies the page frame number of the page that
+ is changed.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ return;
+}
+
+VOID
+HalFlushDcachePage (
+ IN PVOID Color,
+ IN ULONG PageFrame,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This function flushes (invalidates) up to a page of data from the
+ data cache.
+
+Arguments:
+
+ Color - Supplies the starting virtual address and color of the
+ data that is flushed.
+ PageFrame - Supplies the page frame number of the page that
+ is flushed.
+
+ Length - Supplies the length of the region in the page that is
+ flushed.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ return;
+}
+
+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.
+
+--*/
+{
+
+ if (ReadOperation) {
+ HalpMb(); // force all previous writes off chip
+ HalpMb(); // not issued until previous mb completes
+ if (Mdl->MdlFlags & MDL_IO_PAGE_READ) {
+
+ //
+ // The operation is a page read, thus the istream must
+ // be flushed.
+ //
+ HalpImb();
+ }
+ }
+
+}
+
+VOID
+HalPurgeDcachePage (
+ IN PVOID Color,
+ IN ULONG PageFrame,
+ IN ULONG Length
+ )
+/*++
+Routine Description:
+
+ This function purges (invalidates) up to a page of data from the
+ data cache.
+
+Arguments:
+
+ Color - Supplies the starting virtual address and color of the
+ data that is purged.
+
+ PageFrame - Supplies the page frame number of the page that
+ is purged.
+
+ Length - Supplies the length of the region in the page that is
+ purged.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ return;
+}
+
+
+VOID
+HalPurgeIcachePage (
+ IN PVOID Color,
+ IN ULONG PageFrame,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This function purges (invalidates) up to a page fo data from the
+ instruction cache.
+
+Arguments:
+
+ Color - Supplies the starting virtual address and color of the
+ data that is purged.
+
+ PageFrame - Supplies the page frame number of the page that
+ is purged.
+
+ Length - Supplies the length of the region in the page that is
+ purged.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // The call to HalpImb calls PAL to flush the Icache, which ensures that
+ // any stale hits will be invalidated
+ //
+ HalpImb;
+}
+
+VOID
+HalSweepDcache (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function sweeps (invalidates) the entire data cache.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ return;
+}
+
+VOID
+HalSweepDcacheRange (
+ IN PVOID BaseAddress,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This function flushes the specified range of addresses from the data
+ cache on the current processor.
+
+Arguments:
+
+ BaseAddress - Supplies the starting physical address of a range of
+ physical addresses that are to be flushed from the data cache.
+
+ Length - Supplies the length of the range of physical addresses
+ that are to be flushed from the data cache.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ return;
+}
+
+VOID
+HalSweepIcache (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function sweeps (invalidates) the entire instruction cache.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // The call to HalpImb calls PAL to flush the Icache, which ensures that
+ // any stale hits will be invalidated
+ //
+ HalpImb;
+ return;
+}
+
+VOID
+HalSweepIcacheRange (
+ IN PVOID BaseAddress,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This function flushes the specified range of addresses from the
+ instruction cache on the current processor.
+
+Arguments:
+
+ BaseAddress - Supplies the starting physical address of a range of
+ physical addresses that are to be flushed from the instruction cache.
+
+ Length - Supplies the length of the range of physical addresses
+ that are to be flushed from the instruction cache.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // The call to HalpImb calls PAL to flush the Icache, which ensures that
+ // any stale hits will be invalidated
+ //
+ HalpImb;
+
+}
+
+VOID
+HalZeroPage (
+ IN PVOID NewColor,
+ IN PVOID OldColor,
+ IN ULONG PageFrame
+ )
+/*++
+
+Routine Description:
+
+ This function zeros a page of memory.
+
+Arguments:
+
+ NewColor - Supplies the page aligned virtual address of the
+ new color of the page that is zeroed.
+
+ OldColor - Supplies the page aligned virtual address of the
+ old color of the page that is zeroed.
+
+ PageFrame - Supplies the page frame number of the page that
+ is zeroed.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PVOID tmp;
+
+ tmp = (PVOID)((PageFrame << PAGE_SHIFT) | KSEG0_BASE);
+
+ RtlZeroMemory(tmp, PAGE_SIZE);
+}
+
+VOID
+KeFlushWriteBuffer (
+ VOID
+ )
+
+{
+ //
+ // We flush the write buffer by doing a series of memory
+ // barrier operations. It still isn't clear if we need
+ // to do two/four of them to flush the buffer, or if one
+ // to order the writes is suffcient
+ //
+
+ HalpMb;
+ return;
+}
+
+VOID
+KeFlushDcache (
+ IN BOOLEAN AllProcessors,
+ IN PVOID BaseAddress OPTIONAL,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This function flushes the data cache on all processors that are currently
+ running threads which are children of the current process or flushes the
+ data cache on all processors in the host configuration.
+
+Arguments:
+
+ AllProcessors - Supplies a boolean value that determines which data
+ caches are flushed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(BaseAddress);
+ UNREFERENCED_PARAMETER(Length);
+
+ HalFlushDcache(AllProcessors);
+ return;
+}
+
+VOID
+HalFlushDcache (
+ IN BOOLEAN AllProcessors
+ )
+
+/*++
+
+Routine Description:
+
+ This function flushes the data cache on all processors that are currently
+ running threads which are children of the current process or flushes the
+ data cache on all processors in the host configuration.
+
+Arguments:
+
+ AllProcessors - Supplies a boolean value that determines which data
+ caches are flushed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Sweep (index/writeback/invalidate) the data cache.
+ //
+
+ HalSweepDcache();
+ 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 8;
+}
diff --git a/private/ntos/nthals/hal0jens/alpha/jxcalstl.c b/private/ntos/nthals/hal0jens/alpha/jxcalstl.c
new file mode 100644
index 000000000..651eab2db
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/jxcalstl.c
@@ -0,0 +1,148 @@
+#if defined(JENSEN)
+
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1992 Digital Equipment Corporation
+
+Module Name:
+
+ jxcalstl.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 an Alpha/Jensen system.
+
+Author:
+
+ David N. Cutler (davec) 26-Apr-1991
+ Jeff McLeman (mcleman) 09-Jun-1992
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+ Jeff McLeman 09-Jun-92
+ Make a Alpha/Jensen specific version of this file.
+
+--*/
+
+#include "halp.h"
+#include "stdio.h"
+#include "jnsndef.h"
+#include "jnsnrtc.h"
+
+
+
+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.
+
+--*/
+
+{
+
+ CHAR Buffer[128];
+ ULONG Index;
+ KIRQL OldIrql;
+
+ //
+ // Set the time increment value and connect the real clock interrupt
+ // routine.
+ //
+
+ PCR->InterruptRoutine[CLOCK2_LEVEL] = HalpClockInterrupt;
+
+ 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.
+
+--*/
+
+{
+ HalpStallExecution(MicroSeconds);
+ 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.
+
+--*/
+
+{
+
+ UCHAR data;
+
+ //
+ // Acknowledge the clock interrupt.
+ //
+
+
+ HalpWriteVti( RTC_APORT, RTC_CONTROL_REGISTERC );
+ data = HalpReadVti( RTC_DPORT );
+
+
+ return;
+}
+
+#endif
diff --git a/private/ntos/nthals/hal0jens/alpha/jxclock.c b/private/ntos/nthals/hal0jens/alpha/jxclock.c
new file mode 100644
index 000000000..918a7a22b
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/jxclock.c
@@ -0,0 +1,311 @@
+/*++
+
+Copyright (c) 1992 Digital Equipment Corporation
+
+Module Name:
+
+ jxclock.c
+
+Abstract:
+
+ This module handles the RTC interrupt ,Profile Counter
+ interupt and all Profile counter functions for the
+ Alpha/Jensen paltform.
+
+Author:
+
+ Jeff McLeman (mcleman) 05-June-1992
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+ Rod Gamache [DEC] 9-Mar-1993
+ Fix profile clock.
+
+
+--*/
+
+#include "halp.h"
+#include "jnsnrtc.h"
+#include "eisa.h"
+#include "jxprof.h"
+
+//
+// Define global data.
+//
+
+//
+// Values used for Profile Clock
+//
+
+// Convert the interval to rollover count for 8254 timer. Since
+// the 8254 counts down a 16 bit value at the clock rate of 1.193 MHZ,
+// the computation is:
+//
+// RolloverCount = (Interval * 0.0000001) * (1193 * 1000000)
+// = Interval * .1193
+// = Interval * 1193 / 10000
+
+#define PROFILE_INTERVAL 1193
+#define PROFILE_INTERVALS_PER_100NS 10000/1193
+#define MIN_PROFILE_TICKS 4
+#define MAX_PROFILE_TICKS 0x10000 // 16 bit counter (zero is max)
+
+//
+// Since the profile timer interrupts at a frequency of 1.193 MHZ, we
+// have .1193 intervals each 100ns. So we need a more reasonable value.
+// If we compute the timer based on 1600ns intervals, we get 16 * .1193 or
+// about 1.9 ticks per 16 intervals.
+//
+// We round this to 2 ticks per 1600ns intervals.
+//
+
+#define PROFILE_TIMER_1600NS_TICKS 2
+
+//
+// Default Profile Interval to be about 1ms.
+//
+
+ULONG HalpProfileInterval = PROFILE_TIMER_1600NS_TICKS * PROFILE_INTERVALS_PER_100NS * 10000 / 16; // ~1ms
+
+//
+// Default Number of Profile Clock Ticks per sample
+//
+
+ULONG HalpNumberOfTicks = 1;
+
+//
+// HalpRpccTime is the software maintained 64-bit processor cycle counter.
+//
+
+LARGE_INTEGER HalpRpccTime;
+
+//
+// Define global data used to communicate new clock rates to the clock
+// interrupt service routine.
+//
+
+ULONG HalpCurrentTimeIncrement;
+ULONG HalpNextRateSelect;
+ULONG HalpNextTimeIncrement;
+ULONG HalpNewTimeIncrement;
+
+
+VOID
+HalpProgramIntervalTimer(
+ IN ULONG RateSelect
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called to program the interval timer. It is used during
+ Phase 1 initialization to start the heartbeat timer. It also used by
+ the clock interrupt interrupt routine to change the hearbeat timer rate
+ when a call to HalSetTimeIncrement has been made in the previous time slice.
+
+Arguments:
+
+ RateSelect - Supplies rate select to be placed in the clock.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG DataByte;
+
+ //
+ // Set the new rate
+ //
+ DataByte = 0;
+ ((PRTC_CONTROL_REGISTER_A)(&DataByte))->RateSelect = RateSelect;
+ HalpWriteVti( RTC_APORT, RTC_CONTROL_REGISTERA );
+ HalpWriteVti( RTC_DPORT, DataByte );
+
+ //
+ // Set the correct mode
+ //
+ DataByte = 0;
+ ((PRTC_CONTROL_REGISTER_B)(&DataByte))->TimerInterruptEnable = 1;
+ ((PRTC_CONTROL_REGISTER_B)(&DataByte))->HoursFormat = 1;
+ ((PRTC_CONTROL_REGISTER_B)(&DataByte))->DataMode = 1;
+ HalpWriteVti( RTC_APORT, RTC_CONTROL_REGISTERB );
+ HalpWriteVti( RTC_DPORT, DataByte );
+}
+
+
+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.
+
+Arguments:
+
+ DesiredIncrement - Supplies desired number of 100ns units between clock
+ interrupts.
+
+Return Value:
+
+ The actual time increment in 100ns units.
+
+--*/
+
+{
+ ULONG NewTimeIncrement;
+ ULONG NextRateSelect;
+ 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);
+ if (DesiredIncrement < MINIMUM_INCREMENT) {
+ DesiredIncrement = MINIMUM_INCREMENT;
+ }
+ if (DesiredIncrement > MAXIMUM_INCREMENT) {
+ DesiredIncrement = MAXIMUM_INCREMENT;
+ }
+
+ //
+ // Find the allowed increment that is less than or equal to
+ // the desired increment.
+ //
+ if (DesiredIncrement >= RTC_PERIOD_IN_CLUNKS4) {
+ NewTimeIncrement = RTC_PERIOD_IN_CLUNKS4;
+ NextRateSelect = RTC_RATE_SELECT4;
+ } else if (DesiredIncrement >= RTC_PERIOD_IN_CLUNKS3) {
+ NewTimeIncrement = RTC_PERIOD_IN_CLUNKS3;
+ NextRateSelect = RTC_RATE_SELECT3;
+ } else if (DesiredIncrement >= RTC_PERIOD_IN_CLUNKS2) {
+ NewTimeIncrement = RTC_PERIOD_IN_CLUNKS2;
+ NextRateSelect = RTC_RATE_SELECT2;
+ } else {
+ NewTimeIncrement = RTC_PERIOD_IN_CLUNKS1;
+ NextRateSelect = RTC_RATE_SELECT1;
+ }
+
+ HalpNextRateSelect = NextRateSelect;
+ HalpNewTimeIncrement = NewTimeIncrement;
+
+ KeLowerIrql(OldIrql);
+
+ return NewTimeIncrement;
+}
+
+
+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.
+
+--*/
+
+{
+
+ LARGE_INTEGER LocalRpccTime;
+ ULONG RpccValue;
+
+ //
+ // Obtain the current value of the processor cycle counter and adjust
+ // the upper 32 bits if a roll-over occurred since the last time the
+ // Rpcc value was checked (at least oncce per clock interrupt). This
+ // code may be interrupted so we must fetch HalpRpccTimec atomically.
+ //
+
+ *(PULONGLONG)&LocalRpccTime = *(PULONGLONG)&HalpRpccTime;
+ RpccValue = HalpRpcc();
+ if (RpccValue < LocalRpccTime.LowPart) {
+ LocalRpccTime.HighPart += 1;
+ }
+ LocalRpccTime.LowPart = RpccValue;
+
+ //
+ // If the frequency parameter is specified, then return the performance
+ // counter frequency as the current system time frequency.
+ //
+
+ if (ARGUMENT_PRESENT(Frequency) != FALSE) {
+ Frequency->LowPart = HalpClockFrequency;
+ Frequency->HighPart = 0;
+ }
+
+ //
+ // Return the current processor cycle counter as the function value.
+ //
+
+ return LocalRpccTime;
+}
+
+
+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.
+
+--*/
+
+{
+
+ //
+ // ****** Warning ******
+ //
+ // This is a stub routine. It should clear the current value of the
+ // performance counter. It is really only needed in an MP system where,
+ // close, but not exact synchronization of the performance counters
+ // are needed. See MIPS code in halfxs\mips\j4prof.c for a method of
+ // synchronizing.
+ //
+
+ return;
+}
+
diff --git a/private/ntos/nthals/hal0jens/alpha/jxdisp.c b/private/ntos/nthals/hal0jens/alpha/jxdisp.c
new file mode 100644
index 000000000..3fe848081
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/jxdisp.c
@@ -0,0 +1,752 @@
+#if defined (JENSEN)
+
+/*++
+
+Copyright (c) 1992 Digital Equipment Corporation
+
+Module Name:
+
+ jxdisp.c
+
+Abstract:
+
+ This module implements the HAL display initialization and output routines
+ for the Alpha Jensen system
+
+ It was stolen from a combination of the jxdisp.c routine in the firmware
+ directory, written by John DeRosa, and the jxdisp.c routines in the MIPS
+ HAL directory.
+
+Author:
+
+ Miche Baker-Harvey (miche) 10-Jun-1992
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ 12-July-1994 Eric Rehm
+ Support RESET_DISPLAY_PARAMETERS callback registered during
+ HalAcquireDisplayOwnership. This callback is supplied by
+ the Video Miniport driver's HwResetHw entry in the HW_INITIALIZATION_DATA
+ structure.
+
+ 17-Feb-1994 Eric Rehm
+ Rewrite ouput routines to be device-independent through callback
+ to firmware VenPrint routine.
+
+ 04-Mar-1993 Joe Mitchell (DEC)
+ Modify HalpScrollDisplay to pause after displaying each screenful of
+ information during a bugcheck.
+ Modify InitializeVGA to call the firmware to init the video display
+ rather than doing the initialization itself.
+
+ 10-Aug-1992 Jeff McLeman (DEC)
+ Put in debug fixes.
+
+ 22-Jul-1992 Jeff McLeman (mcleman)
+ Remove inline asm(MB)s , because Hal access routines manage
+ read/write ordering.
+
+--*/
+
+//
+// Need some include files here
+#include "halp.h"
+#include "arc.h"
+#include "halvga.h"
+#include "jnsndef.h"
+#include "fwcallbk.h"
+
+
+//
+// Define forward referenced procedure prototypes.
+//
+
+VOID
+HalpDisplayCharacter (
+ IN UCHAR Character
+ );
+
+VOID
+HalpSetLoc (
+ );
+
+BOOLEAN
+InitializeDisplay (
+ );
+
+BOOLEAN
+HalpInitializeDisplay (
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ );
+
+VOID
+HalpScrollDisplay(
+ VOID
+ );
+
+VOID
+HalpFlushKeyboardBuffer (
+ VOID
+ );
+
+VOID
+HalpWaitForKeyPress (
+ VOID
+ );
+typedef
+ULONG
+(*PFW_INITIALIZE_VIDEO_CALLBACK) (
+ OUT ULONG AlphaVideoType
+ );
+
+
+//
+// Define static data.
+//
+
+BOOLEAN HalpBootDisplay = TRUE;
+BOOLEAN HalpDisplayInitialized = FALSE;
+BOOLEAN HalpDisplayOwnedByHal;
+ULONG HalpColumn;
+ULONG HalpRow;
+PUCHAR HalpDestination;
+ULONG HalpForegroundColor;
+ULONG HalpBackgroundColor;
+ULONG DisplayWidth;
+ULONG DisplayHeight;
+ULONG MaxRow;
+ULONG MaxColumn;
+ULONG HalpNewTopLine;
+
+#define CONTROL_SEQUENCE_MAX_PARAMETER 10
+ULONG Parameter[CONTROL_SEQUENCE_MAX_PARAMETER];
+
+PHAL_RESET_DISPLAY_PARAMETERS HalpResetDisplayParameters;
+
+//
+// Declare externally defined data.
+//
+// none.
+
+
+BOOLEAN
+HalpInitializeDisplay (
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes and clears the display.
+
+ This is called during phase 0 of the Hal initialization.
+
+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.
+
+--*/
+
+{
+
+ //
+ // Initialize static data.
+ //
+
+ HalpColumn = 0;
+ HalpRow = 0;
+
+ //
+ // Initialize the display controller.
+ //
+
+ if (InitializeDisplay() == TRUE) {
+
+ //
+ // Mark the display as successfully initialized.
+ //
+
+ HalpDisplayInitialized = TRUE;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+BOOLEAN
+InitializeDisplay (
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes and clears the display.
+
+ It is initialized to: alphanumeric mode, 16 colors fore & background,
+ 8x16 pixel fonts, 80x25 characters, 640 x 400 display.
+ This is not ARC compliant (no underline, no monochrome support)
+ but its good enough for now and can be enhanced later. (For booting,
+ the ARC spec is overkill anyway.)
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ If the video was initialized, TRUE is returned, otherwise FALSE
+
+--*/
+
+{
+ ULONG UnusedParameter;
+ PARC_DISPLAY_STATUS DisplayStatus;
+ char String[16];
+
+ //
+ // Initialize static data.
+ //
+
+ HalpForegroundColor = FW_COLOR_HI_WHITE;
+ HalpBackgroundColor = FW_COLOR_BLUE;
+
+ DisplayStatus = ArcGetDisplayStatus(ARC_CONSOLE_OUTPUT);
+ DisplayWidth = DisplayStatus->CursorMaxXPosition;
+ DisplayHeight = DisplayStatus->CursorMaxYPosition;
+
+ MaxRow = DisplayHeight -1;
+ MaxColumn = DisplayWidth -1;
+ HalpNewTopLine = 0;
+
+ //
+ // [ecr] Call the video driver to intialize the video display,
+ // if it has supplied a reset routine.
+ //
+
+ if (HalpResetDisplayParameters) {
+ HalpDisplayOwnedByHal = HalpResetDisplayParameters(MaxColumn+1, MaxRow+1);
+ }
+
+ //
+ // [jrm] Call the firmware to initialize the video display.
+ //
+
+ if (HalpDisplayOwnedByHal == FALSE) {
+ VenVideoDisplayInitialize(&UnusedParameter);
+ }
+
+ //
+ // Initialize the current display column, row, and ownership values.
+ //
+
+ HalpDisplayOwnedByHal = TRUE;
+
+ //
+ // Set the video memory to blue.
+ //
+
+ sprintf(String, "%c%dm%c%2J", ASCII_CSI, HalpBackgroundColor+40,
+ ASCII_CSI);
+ VenPrint(String);
+
+ 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:
+
+ ResetDisplayParameters - if non-NULL the address of a function
+ the hal can call to reset the video card. The function returns
+ TRUE if the display was reset.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Set HAL ownership of the display to false.
+ //
+
+ HalpDisplayOwnedByHal = FALSE;
+ HalpBootDisplay = FALSE;
+ HalpResetDisplayParameters=ResetDisplayParameters;
+
+ //
+ // Reset the display to begin in the upper left corner.
+ //
+
+ HalpColumn = 0;
+ HalpRow = 0;
+
+ return;
+}
+
+VOID
+HalpVideoReboot(
+ VOID
+ )
+{
+
+ if (HalpResetDisplayParameters && !HalpDisplayOwnedByHal) {
+
+ //
+ // Video work-around. The video driver has a reset function,
+ // call it before resetting the system in case the bios doesn't
+ // know how to reset the display's video mode.
+ //
+
+ HalpResetDisplayParameters(MaxColumn+1, MaxRow+1);
+ }
+}
+
+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;
+
+ //
+ // Note that the MIPS version of this routine goes through mapping
+ // the device into the users space; since we have reserved the top
+ // PDE in system space, we dont have to do this - its always mapped.
+ //
+
+ //
+ // Check if the display has already been successfully initialized.
+ // If it has not then we cannot print on the display.
+ //
+
+ if( HalpDisplayInitialized != TRUE ){
+
+#if (DBG) || (HALDBG)
+
+ DbgPrint( "HDS: %s\n", String );
+
+#endif //DBG || HALDBG
+
+ return;
+
+ }
+
+ //
+ // If ownership of the display has been switched to the system display
+ // driver, then reinitialize the display controller and revert ownership
+ // to the HAL.
+ //
+
+ KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+
+ if (HalpDisplayOwnedByHal == FALSE) {
+ InitializeDisplay();
+ }
+
+ while (*String)
+ {
+ switch (*String)
+ {
+ case '\n':
+ if (HalpRow == MaxRow-1-1) {
+ HalpScrollDisplay();
+ } else {
+ ++HalpRow;
+ }
+ HalpColumn = 0;
+ break;
+
+ case '\b':
+ if(HalpColumn != 0) {
+ --HalpColumn;
+ }
+ break;
+
+ case '\r':
+ HalpColumn = 0;
+ break;
+
+ default:
+ if (HalpColumn > MaxColumn)
+ {
+ if (HalpRow == MaxRow-1-1) {
+ HalpScrollDisplay();
+ } else {
+ ++HalpRow;
+ }
+ HalpColumn = 0;
+ }
+ HalpDisplayCharacter(*String);
+ HalpColumn++;
+ }
+ ++String;
+ }
+
+ KeLowerIrql(OldIrql);
+
+ 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 = DisplayWidth;
+ *HeightInLines = DisplayHeight;
+ *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 > DisplayWidth) {
+ CursorColumn = DisplayWidth;
+ }
+
+ if (CursorRow > DisplayHeight) {
+ CursorRow = DisplayHeight;
+ }
+
+ HalpColumn = CursorColumn;
+ HalpRow = CursorRow;
+ return;
+}
+
+VOID
+HalpDisplayCharacter (
+ IN UCHAR Character
+ )
+
+/*++
+
+Routine Description:
+
+ This routine displays a character at the current x and y positions in
+ the frame buffer.
+
+
+Arguments:
+
+ Character - Supplies a character to be displayed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ char String[16];
+
+ sprintf(String, "%c%d;%dH%c%d;%dm%c",
+ ASCII_CSI, HalpRow+1, HalpColumn+1,
+ ASCII_CSI, HalpForegroundColor+30, HalpBackgroundColor+40,
+ Character);
+ VenPrint(String);
+
+}
+
+
+VOID
+HalpScrollDisplay (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scrolls the display up one line.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PUCHAR Source, Destination;
+ int i;
+ ULONG SaveColumn;
+ char String[16];
+ char *ContinueString = "Press any key to continue...";
+
+ //
+ // If this is not boot time, then we are displaying a bugcheck, and we
+ // do not want it to scroll off the screen before the user has a chance
+ // to read it. Basically, we will track when we do the first line of a
+ // new scroll and we will only ask the user for intervention when the
+ // new line reaches the top of the display.
+ //
+
+ if (HalpBootDisplay == FALSE)
+ {
+ if (HalpNewTopLine == 0)
+ {
+ HalpColumn = 0;
+ HalpRow++;
+ HalpFlushKeyboardBuffer();
+ //
+ // Display a string.
+ //
+ while (*ContinueString) {
+ HalpDisplayCharacter(*ContinueString);
+ ContinueString++;
+ HalpColumn++;
+ }
+ HalpWaitForKeyPress();
+ //
+ // Erase the ContinueString message.
+ //
+ for (HalpColumn = 0; HalpColumn <= MaxColumn ; ++HalpColumn ) {
+ HalpDisplayCharacter(' ');
+ }
+
+ HalpNewTopLine = MaxRow-1-1;
+ HalpRow--;
+ }
+ else {
+ HalpNewTopLine--;
+ }
+ }
+
+ //
+ // Force a FwScrollDisplay by positioning FwRow off the
+ // bottom of the screen and then doing a line feed.
+ //
+
+ sprintf(String, "%c%dB%c", ASCII_CSI, 255, ASCII_LF);
+ VenPrint(String);
+
+}
+
+#define KBD_STATUS_OBF 0x1 /* output buffer full bit */
+#define KBD_STATUS_ODS 0x20 /* data source bit (set for mouse input) */
+#define KBD_STATUS_PORT 0x64
+#define KBD_OUTPUT_BUFFER_PORT 0x60
+
+VOID
+HalpFlushKeyboardBuffer (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine flushes the keyboard buffer.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG KeyboardInput;
+
+ KeyboardInput = inVti(KBD_STATUS_PORT);
+ //DbgPrint("HalpFlushKeyboardBuffer: status=%x\n", KeyboardInput);
+
+ while ((KeyboardInput & KBD_STATUS_OBF) != 0)
+ {
+ HalpStallExecution(1000);
+ KeyboardInput = inVti(KBD_OUTPUT_BUFFER_PORT);
+ //DbgPrint("HalpFlushKeyboardBuffer: input=%x\n", KeyboardInput);
+ HalpStallExecution(1000);
+ KeyboardInput = inVti(KBD_STATUS_PORT);
+ }
+}
+
+VOID
+HalpWaitForKeyPress (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine waits for a character to be entered at the keyboard.
+ Ignore mouse input (KBD_STATUS_ODS bit).
+
+ **jrmfix - temporary until keyboard problem resolved
+ When data is received from
+ the keyboard port, make sure that bit 7 is not set. Sometimes (e.g.
+ during an NMI interrupt), garbage characters are entered into the
+ keyboard buffer (with bit 7 set). Any key entered at the keyboard
+ will not have bit 7 set.
+ **jrmfix
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG KeyboardStatus;
+ ULONG KeyboardInput = 0x80;
+
+ KeyboardStatus = inVti(KBD_STATUS_PORT);
+
+ //
+ //jrmfix** Ignore non-ASCII keyboard input (bit 7 set).
+ //
+ while ((KeyboardInput & 0x80) != 0)
+ {
+ //
+ // Wait for a key to be entered. Ignore any mouse input.
+ //
+ while (((KeyboardStatus & KBD_STATUS_OBF) == 0) ||
+ ((KeyboardStatus & KBD_STATUS_ODS) != 0))
+ {
+ //
+ // If this is mouse input, read from the output port to reset
+ // the status register (KBD_STATUS_PORT).
+ //
+ if (KeyboardStatus & KBD_STATUS_ODS) {
+ HalpStallExecution(1000);
+ KeyboardStatus = inVti(KBD_OUTPUT_BUFFER_PORT);
+ DbgPrint("HalpWaitForKeyPress: MouseInput=%x\n",
+ KeyboardStatus);
+ }
+ HalpStallExecution(1000);
+ KeyboardStatus = inVti(KBD_STATUS_PORT);
+ }
+
+ HalpStallExecution(1000);
+ KeyboardInput = inVti(KBD_OUTPUT_BUFFER_PORT);
+ DbgPrint("HalpWaitForKeyPress: KeyboardInput=%x\n", KeyboardInput);
+ KeyboardStatus = inVti(KBD_STATUS_PORT);
+ }
+}
+
+#endif // JENSEN
diff --git a/private/ntos/nthals/hal0jens/alpha/jxenv.h b/private/ntos/nthals/hal0jens/alpha/jxenv.h
new file mode 100644
index 000000000..90763ef56
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/jxenv.h
@@ -0,0 +1,160 @@
+/*++
+
+Copyright (c) 1992 Digital Equipment Corporation
+
+Module Name:
+
+ xxenv.h
+
+Abstract:
+
+ This module contains definitions for environment variable support
+ under the HAL. (Parts taken from J. Derosa's FWP.H)
+
+Author:
+
+ Jeff McLeman (DEC) 17-Sep-1992
+
+Revision History:
+
+--*/
+
+
+
+//
+// If any aspect of the NVRAM component / configuration data structure
+// is changed for the Alpha/Jensen machine, the module jencds.c may also need
+// to be changed.
+//
+
+
+//
+// Define the private configuration packet structure, which contains a
+// configuration component as well as pointers to the component's parent,
+// peer, child, and configuration data.
+//
+
+typedef struct _CONFIGURATION_PACKET {
+ CONFIGURATION_COMPONENT Component;
+ struct _CONFIGURATION_PACKET *Parent;
+ struct _CONFIGURATION_PACKET *Peer;
+ struct _CONFIGURATION_PACKET *Child;
+ PVOID ConfigurationData;
+} CONFIGURATION_PACKET, *PCONFIGURATION_PACKET;
+
+//
+// The compressed configuration packet structure used to store configuration
+// data in NVRAM.
+//
+
+typedef struct _COMPRESSED_CONFIGURATION_PACKET {
+ UCHAR Parent;
+ UCHAR Class;
+ UCHAR Type;
+ UCHAR Flags;
+ ULONG Key;
+ UCHAR Version;
+ UCHAR Revision;
+ USHORT ConfigurationDataLength;
+ USHORT Identifier;
+ USHORT ConfigurationData;
+} COMPRESSED_CONFIGURATION_PACKET, *PCOMPRESSED_CONFIGURATION_PACKET;
+
+//
+// Defines for Identifier index.
+//
+
+#define NO_CONFIGURATION_IDENTIFIER 0xFFFF
+
+//
+// Defines for the volatile and non-volatile configuration tables.
+//
+
+#define NUMBER_OF_ENTRIES 104
+#define LENGTH_OF_IDENTIFIER 2000
+#define LENGTH_OF_DATA 2048
+#define LENGTH_OF_ENVIRONMENT 1500
+#define LENGTH_OF_EISA_DATA 2500
+
+#define MAXIMUM_ENVIRONMENT_VALUE 256
+#define MAX_NUMBER_OF_ENVIRONMENT_VARIABLES 28
+
+//
+// The volatile configuration table structure.
+//
+
+typedef struct _CONFIGURATION {
+ CONFIGURATION_PACKET Packet[NUMBER_OF_ENTRIES];
+ UCHAR Identifier[LENGTH_OF_IDENTIFIER];
+ UCHAR Data[LENGTH_OF_DATA];
+ UCHAR EisaData[LENGTH_OF_EISA_DATA];
+} CONFIGURATION, *PCONFIGURATION;
+
+//
+// The non-volatile configuration table structure.
+//
+
+typedef struct _NV_CONFIGURATION {
+ COMPRESSED_CONFIGURATION_PACKET Packet[NUMBER_OF_ENTRIES];
+ UCHAR Identifier[LENGTH_OF_IDENTIFIER];
+ UCHAR Data[LENGTH_OF_DATA];
+ UCHAR Checksum1[4];
+ UCHAR Environment[LENGTH_OF_ENVIRONMENT];
+ UCHAR Checksum2[4];
+ UCHAR EisaData[LENGTH_OF_EISA_DATA];
+ UCHAR Checksum3[4];
+} NV_CONFIGURATION, *PNV_CONFIGURATION;
+
+//
+// Define identifier index, data index, pointer to configuration table, and
+// the system identifier.
+//
+
+extern ULONG IdentifierIndex;
+extern ULONG DataIndex;
+extern ULONG EisaDataIndex;
+extern SYSTEM_ID SystemId;
+
+
+
+//
+// PROM layout.
+//
+
+#define PROM_VIRTUAL_BASE 0xA0D00000
+
+//
+// Start of firmware executable code. Code lives in blocks 7, 8, 9, A and B.
+//
+#define PROM_PAGE7 ( PROM_VIRTUAL_BASE+0x70000 )
+
+
+//
+// Component Data Structure, environment variables.
+// These contain their own checksums.
+//
+#define PROM_PAGEC ( PROM_VIRTUAL_BASE+0xC0000 )
+#define NVRAM_CONFIGURATION PROM_PAGEC
+
+//
+// Alpha/Jensen PROM command definitions.
+//
+
+#define PROM_ERASE_SETUP 0x20
+#define PROM_ERASE_CONFIRM 0xD0
+#define PROM_BYTEWRITE_SETUP 0x40
+#define PROM_READ_STATUS 0x70
+#define PROM_CLEAR_STATUS 0x50
+#define PROM_READ_ARRAY 0xff
+
+//
+// The following structures are used for the timer mechanism for
+// updating the ROM
+//
+
+typedef struct _PROMTIMER_ {
+ KTIMER Timer;
+ KDPC Dpc;
+} PROMTIMER, *PPROMTIMER;
+
+
diff --git a/private/ntos/nthals/hal0jens/alpha/jxhalp.h b/private/ntos/nthals/hal0jens/alpha/jxhalp.h
new file mode 100644
index 000000000..1f1126f81
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/jxhalp.h
@@ -0,0 +1,188 @@
+/*++ BUILD Version: 0001 // Increment this if a change has global effects
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1992 Digital Equipment Corporation
+
+Module Name:
+
+ jxhalp.h
+
+Abstract:
+
+ This header file defines the private Hardware Architecture Layer (HAL)
+ Jensen specific interfaces, defines and structures.
+
+Author:
+
+ Jeff Havens (jhavens) 20-Jun-91
+ Miche Baker-Harvey (miche) 13-May-92
+
+
+Revision History:
+ 21-Jul-1992 Jeff McLeman (mcleman)
+ Modify adpater object structure to reflect what we are
+ using.
+
+
+ MBH - Stole Jazz version of this file, since it also uses the 82357 for EISA
+
+--*/
+
+// Might get in trouble for using the same define as Jazz?? MBH
+
+#ifndef _JXHALP_
+#define _JXHALP_
+
+#include "hal.h"
+
+//
+// Define global data used to locate the EISA control space and the realtime
+// clock registers.
+//
+
+extern PVOID HalpEisaControlBase;
+extern PVOID HalpRealTimeClockBase;
+
+extern BOOLEAN LessThan16Mb;
+
+extern POBJECT_TYPE *IoAdapterObjectType;
+
+//
+// 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 IsaDevice;
+ BOOLEAN MasterDevice;
+ BOOLEAN Width16Bits;
+ BOOLEAN ScatterGather;
+ BOOLEAN EisaAdapter;
+ BOOLEAN Dma32BitAddresses;
+} ADAPTER_OBJECT;
+
+//
+// Define memory region structure
+//
+
+typedef struct _MEMORY_REGION {
+ struct _MEMORY_REGION *Next;
+ ULONG PfnBase;
+ ULONG PfnCount;
+} MEMORY_REGION, *PMEMORY_REGION;
+
+//
+// Define function prototypes.
+//
+
+PADAPTER_OBJECT
+HalpAllocateEisaAdapter(
+ IN PDEVICE_DESCRIPTION DeviceDescription
+ );
+
+BOOLEAN
+HalpCreateEisaStructures(
+ VOID
+ );
+
+VOID
+HalpDisableEisaInterrupt(
+ IN ULONG Vector
+ );
+
+BOOLEAN
+HalpEisaInterruptHandler(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext
+ );
+
+BOOLEAN
+HalpEisaDispatch(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext,
+ IN PKTRAP_FRAME TrapFrame
+ );
+
+VOID
+HalpEisaMapTransfer(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN ULONG Offset,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ );
+
+VOID
+HalpEnableEisaInterrupt(
+ IN ULONG Vector,
+ IN KINTERRUPT_MODE InterruptMode
+ );
+
+//
+// Environment variable support
+//
+
+PCHAR
+HalpEnvironmentLoad(
+ VOID
+ );
+
+VOID
+HalpClearPromStatus(
+ VOID
+ );
+
+VOID
+HalpSetPromReadMode(
+ VOID
+ );
+
+ARC_STATUS
+HalpCheckPromStatusAndClear(
+ IN ULONG WhichToCheck
+ );
+
+ARC_STATUS
+HalpErasePromBlock(
+ IN PUCHAR EraseAddress
+ );
+
+ARC_STATUS
+HalpWritePromByte(
+ IN PUCHAR WriteAddress,
+ IN UCHAR WriteData
+ );
+
+ARC_STATUS
+HalpSaveConfiguration(
+ VOID
+ );
+
+VOID
+HalpInitializeSpecialMemory(
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ );
+
+#endif // _JXHALP_
+
+
+
+
diff --git a/private/ntos/nthals/hal0jens/alpha/jxhltsup.s b/private/ntos/nthals/hal0jens/alpha/jxhltsup.s
new file mode 100644
index 000000000..e5db9fe29
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/jxhltsup.s
@@ -0,0 +1,109 @@
+// TITLE("Halt Interrupt Support")
+//++
+//
+// Copyright (c) 1992 Digital Equipment Corporation
+//
+// Module Name:
+//
+// jxhltsup.s
+//
+// Abstract:
+//
+// This module implements the code necessary to field the halt button
+// interrupt on JENSEN.
+//
+// Author:
+//
+// Joe Notarangelo 18-Dec-1992
+//
+// Environment:
+//
+// Kernel mode only, IRQL halt synchronization level.
+//
+// Revision History:
+//
+//--
+
+#if !(DBG)
+
+//
+// Boolean value that controls whether to break or not for a halt button
+// interrupt on a free build. The default value is zero and must be set
+// in the debugger to a non-zero value to trigger the breakpoint action
+// when the halt button is pressed.
+//
+
+ .data
+
+ .globl HalpHaltButtonBreak
+HalpHaltButtonBreak:
+ .long 0 : 1
+
+#endif //!DBG
+
+
+#include "ksalpha.h"
+
+ SBTTL("Halt Interrupt Support")
+//++
+//
+// Routine Description:
+//
+// This routine is entered as the result of a halt interrupt caused by
+// a human pushing the halt switch on JENSEN. This routine is connected
+// directly into the IDT. The halt interrupt is mechanical and does not
+// require an interrupt acknowledge.
+//
+// Arguments:
+//
+// s6/fp - Supplies a pointer to a trap frame.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ .struct 0
+HaltRa: .space 8 // saved return address
+ .space 8 // fill for alignment
+HaltFrameLength:
+
+ NESTED_ENTRY(HalpHaltInterrupt, ExceptionFrameLength, zero)
+
+ lda sp, -HaltFrameLength(sp) // allocate stack frame
+ stq ra, HaltRa(sp) // save ra
+
+ PROLOGUE_END
+
+
+#if DBG
+
+//
+// Always stop in the debugger if this is a checked build.
+//
+
+ BREAK_DEBUG_STOP // stop in the debugger
+
+#else
+
+//
+// If this is a free build then check the variable HalpHaltButtonBreak,
+// if it is non-zero then take the breakpoint, otherwise ignore it.
+//
+
+ lda t0, HalpHaltButtonBreak // get the address of the boolean
+ ldl t0, 0(t0) // read the boolean
+ beq t0, 10f // if eq, don't stop
+
+ BREAK_DEBUG_STOP // stop in the debugger
+
+10:
+
+#endif //DBG
+
+ ldq ra, HaltRa(sp) // save ra
+ lda sp, HaltFrameLength(sp) // deallocate stack frame
+ ret zero, (ra) // interrupt is dismissed
+
+ .end HalpHaltInterrupt
diff --git a/private/ntos/nthals/hal0jens/alpha/jxhwsup.c b/private/ntos/nthals/hal0jens/alpha/jxhwsup.c
new file mode 100644
index 000000000..94309cb7f
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/jxhwsup.c
@@ -0,0 +1,4290 @@
+#if defined(JENSEN)
+
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+Copyright (c) 1992 Digital Equipment Corporation
+
+Module Name:
+
+ jxhwsup.c
+
+Abstract:
+
+ This module contains the HalpXxx routines for the NT I/O system that
+ are hardware dependent. Were these routines not hardware dependent,
+ they would normally reside in the internal.c module.
+
+Author:
+
+ Jeff Havens (jhavens) 14-Feb-1990
+ Miche Baker-Harvey (miche) 22-May-1992
+ Jeff McLeman (mcleman) 27-May-1992
+
+Environment:
+
+ Kernel mode, local to I/O system
+
+Revision History:
+
+
+--*/
+
+#include "halp.h"
+#include "jnsndef.h"
+#include "jnsnint.h"
+#include "jnsndma.h"
+#include "eisa.h"
+#include "jxisa.h"
+#include "string.h"
+
+
+
+#define HAL_32MB 0x2000000
+
+#define HALF_MEGABYTE 0x80000
+
+#define NUMBER_OF_SPECIAL_REGIONS 6
+
+#define SPECIAL_BUFFER_SIZE NUMBER_OF_SPECIAL_REGIONS*sizeof(MEMORY_REGION)
+
+PVOID HalpEisaControlBase;
+
+//
+// We have one fixed special memory region at half a megabyte.
+//
+
+MEMORY_REGION HalpHalfMeg;
+
+//
+// Pointer to special memory regions that must be checked on every I/O.
+// Use to check if PFN is contained in a special memory region.
+//
+
+PMEMORY_REGION HalpSpecialRegions = NULL;
+
+//
+// Buffers used for MEMORY_REGION descriptors. We cannot allocate non-paged
+// pool when we are building the MEMORY_REGION descriptors. So we will have
+// our own little pool.
+//
+
+UCHAR HalpMemoryRegionFree[SPECIAL_BUFFER_SIZE];
+
+//
+// We have one fixed pool to allocate MEMORY_REGIONS from.
+//
+
+PVOID HalpMemoryRegionBuffers = HalpMemoryRegionFree;
+ULONG HalpMemoryRegionSize = SPECIAL_BUFFER_SIZE;
+
+//
+// The following is the interrupt object used by the DMA controller dispatch
+// routine to provide synchronization to the DMA controller. It is initialized
+// by the I/O system during system initialization.
+//
+
+KINTERRUPT HalpDmaInterrupt;
+
+//
+// The HaeIndex, used in creating QVAs for EISA memory space.
+//
+ULONG HaeIndex;
+
+//
+// This is the HAE table. The first table entry is used to map the lowest
+// 32MB in a Jensen system. The second entry is used to map the next 32MB
+// entry so that graphics cards, etc., will work.
+//
+
+CHAR HalpHaeTable[4] = { 0, 1, 0, 0 };
+
+//
+// The following is an array of adapter object structures for the Eisa DMA
+// channels.
+//
+
+//
+// Define the area for the Eisa objects
+//
+
+PADAPTER_OBJECT HalpEisaAdapter[8];
+
+//
+// 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;
+
+BOOLEAN LessThan16Mb;
+BOOLEAN HalpEisaDma;
+
+IO_ALLOCATION_ACTION
+HalpAllocationRoutine (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ );
+
+BOOLEAN
+HalpGrowMapBuffers(
+ PADAPTER_OBJECT AdapterObject,
+ ULONG Amount
+ );
+
+
+PADAPTER_OBJECT
+HalpAllocateAdapter(
+ IN ULONG MapRegistersPerChannel,
+ IN PVOID AdapterBaseVa,
+ IN PVOID ChannelNumber
+ );
+
+VOID
+HalpCopyBufferMap(
+ IN PMDL Mdl,
+ IN PTRANSLATION_ENTRY translationEntry,
+ IN PVOID CurrentVa,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ );
+
+PVOID
+HalCreateQva(
+ IN PHYSICAL_ADDRESS PA,
+ IN PVOID VA
+ );
+
+ULONG
+HalpGetEisaData(
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+ULONG
+HalpNoBusData (
+ IN PVOID BusHandler,
+ IN PVOID RootHandler,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+BOOLEAN
+HalpSpecialMemory(
+ IN ULONG PFN
+ );
+
+BOOLEAN
+HalpAnySpecialMemory(
+ IN PMDL Mdl,
+ IN ULONG Length,
+ IN ULONG Offset
+ );
+
+
+VOID
+HalpCopyBufferMap(
+ IN PMDL Mdl,
+ IN PTRANSLATION_ENTRY translationEntry,
+ IN PVOID CurrentVa,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine copies the specified data between the user buffer and the
+ map register buffer. First, the user buffer is mapped, if need be then
+ the data is copied. Finally, the user buffer will be unmapped, if need be.
+
+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 xfer.
+
+ 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 - A Boolean value that indicates whether this is a write
+ to the device from memory of vise-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 the map buffer.
+ //
+
+ if (WriteToDevice) {
+
+ RtlMoveMemory( mapAddress, bufferAddress, Length);
+
+ } else {
+
+ RtlMoveMemory ( bufferAddress, mapAddress, Length);
+
+ }
+}
+
+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;
+ ULONG 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 = TRUE;
+
+ } else {
+
+ //
+ // Calculate the map register base from the allocated map
+ // register and base of the master adapter object.
+ //
+
+ 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);
+ }
+
+ if (AdapterObject->EisaAdapter) {
+
+ AdapterObject->MapRegisterBase = (PVOID)
+ ((ULONG) AdapterObject->MapRegisterBase | EISA_ADAPTER);
+
+ }
+ }
+
+ 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);
+
+}
+
+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.
+ NumerOfMapRegisters - Number of map registers required. Updated to show
+ actual number of registers 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;
+
+ if ( MasterAdapter == NULL ) {
+ if ( MasterAdapterObject == NULL ) {
+ AdapterObject->NumberOfMapRegisters = 0;
+ return NULL;
+ } else {
+ MasterAdapter = MasterAdapterObject;
+ AdapterObject->MapRegistersPerChannel = 16;
+ }
+ }
+
+ //
+ // Check to see whether this driver needs to allocate any map registers.
+ //
+
+ //
+ // 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 = (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);
+ }
+
+ if (AdapterObject->EisaAdapter) {
+ AdapterObject->MapRegisterBase = (PVOID)
+ ((ULONG) AdapterObject->MapRegisterBase | EISA_ADAPTER);
+ }
+
+ return AdapterObject->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 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);
+
+ //
+ // Assume below 16M to support ISA devices
+ //
+
+ physicalAddress.LowPart = MAXIMUM_ISA_PHYSICAL_ADDRESS-1;
+ physicalAddress.HighPart = 0;
+
+ //
+ // If the caller supports 32bit addresses, and it's a master, let
+ // it have any memory below 1G
+ //
+
+ if (AdapterObject->Dma32BitAddresses && AdapterObject->MasterDevice) {
+ physicalAddress.LowPart = 0xFFFFFFFF;
+ }
+
+ //
+ // Allocate the actual buffer.
+ //
+
+ virtualAddress = MmAllocateContiguousMemory(
+ Length,
+ physicalAddress
+ );
+
+ if (!HALP_IS_PHYSICAL_ADDRESS(virtualAddress)) {
+
+ *LogicalAddress = MmGetPhysicalAddress(virtualAddress);
+
+ } else {
+
+ LogicalAddress->QuadPart = (ULONG)virtualAddress & (~KSEG0_BASE);
+
+ }
+ 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.
+
+--*/
+
+{
+
+ 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(VirtualAddress);
+
+
+}
+
+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 deivce.
+
+ 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;
+ PVOID adapterBaseVa;
+ ULONG channelNumber;
+ ULONG controllerNumber;
+ DMA_EXTENDED_MODE extendedMode;
+ UCHAR adapterMode;
+ ULONG numberOfMapRegisters;
+ BOOLEAN useChannel;
+ ULONG maximumLength;
+ UCHAR DataByte;
+
+ //
+ // 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;
+ }
+
+ //
+ // 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) {
+
+ HalpEisaDma = FALSE;
+
+ WRITE_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort.Channel2, 0x55);
+ DataByte = READ_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->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.
+ //
+
+ 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) &((PEISA_CONTROL) HalpEisaControlBase)->Dma1BasePort;
+
+ } else {
+
+ controllerNumber = 2;
+ adapterBaseVa = &((PEISA_CONTROL) HalpEisaControlBase)->Dma2BasePort;
+
+ }
+
+ //
+ // Determine if a new adapter object is necessary. If so then allocate it.
+ //
+
+ if (useChannel && HalpEisaAdapter[DeviceDescriptor->DmaChannel] != NULL) {
+
+ adapterObject = HalpEisaAdapter[DeviceDescriptor->DmaChannel];
+
+ 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) {
+
+ HalpEisaAdapter[DeviceDescriptor->DmaChannel] = adapterObject;
+
+ }
+
+ //
+ // Set the maximum number of map registers for this channel bus to
+ // the number requested and the type of device.
+ //
+
+ if (numberOfMapRegisters) {
+
+ //
+ // The speicified 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 * 2;
+
+ } 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 &&
+ MasterAdapterObject->CommittedMapRegisters -
+ MasterAdapterObject->NumberOfMapRegisters >
+ MAXIMUM_ISA_MAP_REGISTER ) {
+
+ 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->Dma32BitAddresses = DeviceDescriptor->Dma32BitAddresses;
+ adapterObject->ScatterGather = DeviceDescriptor->ScatterGather;
+ *NumberOfMapRegisters = adapterObject->MapRegistersPerChannel;
+
+ if (DeviceDescriptor->Master) {
+
+ adapterObject->MasterDevice = TRUE;
+
+ } else {
+
+ adapterObject->MasterDevice = FALSE;
+
+ }
+
+ //
+ // Indicate whether the device is an Eisa adapter.
+ //
+
+ if ( DeviceDescriptor->InterfaceType == Eisa ) {
+ adapterObject->EisaAdapter = TRUE;
+ } else {
+ adapterObject->EisaAdapter = 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 =
+ &((PEISA_CONTROL) HalpEisaControlBase)->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 =
+ &((PEISA_CONTROL) HalpEisaControlBase)->Dma2ExtendedModePort;
+
+ }
+
+
+ adapterObject->Width16Bits = FALSE;
+
+ if (HalpEisaDma) {
+
+ //
+ // Initialzie the extended mode port.
+ //
+
+ *((PUCHAR) &extendedMode) = 0;
+ extendedMode.ChannelNumber = 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_PORT_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_PORT_UCHAR( &dmaControl->Mode, adapterMode );
+
+ //
+ // Unmask the DMA channel.
+ //
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber)
+ );
+
+ } else {
+
+ //
+ // This request is for DMA controller 1
+ //
+
+ PDMA2_CONTROL dmaControl;
+
+ dmaControl = adapterObject->AdapterBaseVa;
+
+ WRITE_PORT_UCHAR( &dmaControl->Mode, adapterMode );
+
+ //
+ // Unmask the DMA channel.
+ //
+
+ WRITE_PORT_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);
+}
+
+BOOLEAN
+HalpTranslateSystemBusAddress(
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN PHYSICAL_ADDRESS BusAddress,
+ IN OUT PULONG AddressSpace,
+ OUT PPHYSICAL_ADDRESS TranslatedAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This function 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:
+
+ BusHandler - Registered BUSHANDLER for the target configuration space
+ Supplies the bus handler (bus no, interface type).
+
+ RootHandler - Registered BUSHANDLER for the orginating
+ HalTranslateBusAddress request.
+
+ BusAddress - Supplies the bus relative address.
+
+ AddressSpace - Supplies the address space number for the device: 0 for
+ memory and 1 for I/O space. If the desired access mode is user mode,
+ then bit 1 must be TRUE.
+
+ TranslatedAddress - Supplies a pointer to return the translated address
+
+
+Notes:
+
+ This is a variation of what began in the MIPS code. The intel code often
+ assumes that if an address is in I/O space, the bottom 32 bits of the
+ physical address can be used "like" a virtual address, and are returned
+ to the user. This doesn't work on MIPs machines where physical
+ addresses can be larger than 32 bits.
+
+ Since we are using superpage addresses for I/O on Alpha, we can do
+ almost what is done on intel. If AddressSpace is equal to 0 or 1, then
+ we assume the user is doing kernel I/O and we call
+ HalCreateQva to build a Quasi Virtual Address and return
+ that to the caller. We then set AddressSpace to a 1, so that the caller
+ will not call MmMapIoSpace. The Caller will use the low 32 bits of the
+ physical address we return as the VA. (Which we built a QVA in).
+ If the caller wants to access EISA I/O or Memory through user mode, then
+ the caller must set bit 1 in AddressSpace to a 1 (AddressSpace=2 or 3,
+ depending on whether EISA I/O or Memory), then the caller is returned the
+ 34 bit Physical address. The caller will then call MmMapIoSpace, or
+ ZwMapViewOfSection which in turn calls HalCreateQva to build a QVA out
+ of a VA mapped through the page tables.
+
+ **** Note ****
+
+ The QVA in user mode can only be accessed with the routines WRITE/READ_
+ REGISTER_UCHAR/USHORT/ULONG, and they must be the ones in module
+ JXIOUSER.C. The user CANNOT call the above routines in the HAL from
+ usermode. (Which is pointless, since the HAL is superpage access
+ only).
+
+
+
+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
+
+--*/
+
+{
+ INTERFACE_TYPE InterfaceType = BusHandler->InterfaceType;
+ ULONG BusNumber = BusHandler->BusNumber;
+
+ PVOID va = 0; // note, this is used for a placeholder
+
+ HaeIndex = 0;
+
+ //
+ // If this is for the internal bus then the device is on the combo chip.
+ // BusAddress.LowPart should contains the port of the device.
+ //
+
+ if (InterfaceType == Internal) {
+
+ //
+ // Return the passed parameters.
+ //
+
+ TranslatedAddress->HighPart = 1;
+ TranslatedAddress->LowPart = 0xC0000000 + (BusAddress.LowPart << COMBO_BIT_SHIFT);
+
+ //
+ // Now call HalCreateQva. This will create a QVA
+ // that we'll return to the caller. Then we will implicitly set
+ // AddressSpace to a 1. The caller then will not call MmMapIoSpace
+ // and will use the address we return as a VA.
+
+ TranslatedAddress->LowPart = (ULONG) HalCreateQva(
+ *TranslatedAddress, va);
+
+ TranslatedAddress->HighPart = 0; // clear high longword for QVA
+
+ *AddressSpace = 1; // Make sure user doesn't call
+ // MmMapIoSpace.
+
+ return(TRUE);
+ }
+
+ if (InterfaceType != Isa && InterfaceType != Eisa) {
+
+ //
+ // Not on this system return nothing.
+ //
+
+ *AddressSpace = 0;
+ TranslatedAddress->LowPart = 0;
+ return(FALSE);
+ }
+ //
+ // Jensen only has one I/O bus which is an EISA, so the bus number is unused.
+ //
+ // Determine the address based on whether the bus address is in I/O space
+ // or bus memory space.
+ //
+
+ switch (*AddressSpace) {
+
+ case 0 : {
+
+ //
+ // The address is in EISA memory space, kernel mode.
+ //
+
+ //
+ // If the address cannot be mapped into the predefined low 32MB
+ // 'default' region, then find a free or matching region in the HAE
+ // Table. NB: slot zero is predefined to the lowest 32MB and cannot
+ // be overwritten.
+ //
+ if ( BusAddress.LowPart >= HAL_32MB ) {
+ ULONG HaeValue;
+
+ HaeValue = (BusAddress.LowPart >> 25);
+
+ for ( HaeIndex = 1; HaeIndex < 4; HaeIndex++ ) {
+ if ( HalpHaeTable[HaeIndex] == 0 ||
+ HalpHaeTable[HaeIndex] == HaeValue ) {
+ break;
+ }
+ }
+
+ // Check if no HAE slots were available, if so return error.
+
+ if ( HaeIndex == 4 ) {
+ *AddressSpace = 0;
+ TranslatedAddress->LowPart = 0;
+ return(FALSE);
+ } else {
+ HalpHaeTable[HaeIndex] = HaeValue;
+ }
+
+ }
+
+ TranslatedAddress->HighPart = 0x2;
+
+ //
+ // There is no component of the bus address in the low part
+ //
+ TranslatedAddress->LowPart = (BusAddress.LowPart << EISA_BIT_SHIFT);
+
+ //
+ // Now call HalCreateQva. This will create a QVA
+ // that we'll return to the caller. Then we will implicitly set
+ // AddressSpace to a 1. The caller then will not call MmMapIoSpace
+ // and will use the address we return as a VA.
+
+ TranslatedAddress->LowPart = (ULONG) HalCreateQva(
+ *TranslatedAddress, va);
+
+ TranslatedAddress->HighPart = 0; // clear high longword for QVA
+
+ *AddressSpace = 1; // don't let the user call MmMapIoSpace
+
+ return(TRUE);
+
+ }
+
+ case 1 : {
+ //
+ // The address is in EISA I/O space, kernel mode.
+ //
+
+ TranslatedAddress->HighPart = 0x3;
+ //
+ // There is no component of the bus address in the low part
+ //
+ TranslatedAddress->LowPart = (BusAddress.LowPart << EISA_BIT_SHIFT);
+
+ //
+ // Now call HalCreateQva. This will create a QVA
+ // that we'll return to the caller. Then we will implicitly set
+ // AddressSpace to a 1. The caller then will not call MmMapIoSpace
+ // and will use the address we return as a VA.
+
+ TranslatedAddress->LowPart = (ULONG) HalCreateQva(
+ *TranslatedAddress, va);
+
+ TranslatedAddress->HighPart = 0; // clear high longword for QVA
+
+ *AddressSpace = 1; // Make sure user doesn't call
+ // MmMapIoSpace.
+
+ return(TRUE);
+
+ }
+ case 2 : {
+
+ //
+ // The address is in EISA memory space, user mode.
+ //
+
+
+ TranslatedAddress->HighPart = 0x2;
+
+
+ //
+ // There is no component of the bus address in the low part
+ //
+ TranslatedAddress->LowPart = (BusAddress.LowPart << EISA_BIT_SHIFT);
+
+
+ *AddressSpace = 0; // Let the user call MmMapIoSpace
+
+ return(TRUE);
+
+ }
+
+ case 3 : {
+ //
+ // The address is in EISA I/O space, user mode.
+ //
+
+ TranslatedAddress->HighPart = 0x3;
+ //
+ // There is no component of the bus address in the low part
+ //
+ TranslatedAddress->LowPart = (BusAddress.LowPart << EISA_BIT_SHIFT);
+
+
+ *AddressSpace = 0; // Make sure user can call
+ // MmMapIoSpace.
+
+ return(TRUE);
+
+ }
+
+ }
+}
+
+PVOID
+HalCreateQva(
+ IN PHYSICAL_ADDRESS PA,
+ IN PVOID VA
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called two ways. First, from HalTranslateBusAddress,
+ if the caller is going to run in kernel mode and use superpages.
+ The second way is if the user is going to access in user mode.
+ MmMapIoSpace or ZwViewMapOfSection will call this.
+
+ If the input parameter VA is zero, then we assume super page and build
+ a QUASI virtual address that is only usable by calling the hal I/O
+ access routines.
+
+ if the input parameter VA is non-zero, we assume the user has either
+ called MmMapIoSpace or ZwMapViewOfSection and will use the access
+ routines in JXIOUSER.C
+
+ If the PA is not an I/O space address (Combo chip, Eisa I/O, Eisa
+ memory), then return the VA as the QVA.
+
+Arguments:
+
+ PA - the physical address generated by HalTranslateBusAddress
+
+ VA - the virtual address returned by MmMapIoSpace
+
+Return Value:
+
+ The returned value is a quasi virtual address in that it can be
+ added to and subtracted from, but it cannot be used to access the
+ bus directly. The top bits are set so that we can trap invalid
+ accesses in the memory management subsystem. All access should be
+ done through the Hal Access Routines in *ioacc.s if it was a superpage
+ kernel mode access. If it is usermode, then JXIOUSER.C should be built
+ into the users code.
+
+--*/
+{
+
+ PVOID qva;
+
+ if (PA.HighPart == 2) {
+
+ //
+ // in EISA MEMORY space
+ //
+
+ if (VA == 0) {
+
+ //
+ // Remember, the PA.LowPart has already been shifted up 7 bits. We
+ // must first make room at bits <31:30> to insert the HaeIndex.
+ //
+ PA.LowPart = PA.LowPart >> 2;
+ PA.LowPart |= (HaeIndex << 30);
+ qva = (PVOID)(PA.QuadPart >> EISA_BIT_SHIFT-2);
+
+ } else {
+
+ qva = (PVOID)((ULONG)VA >> EISA_BIT_SHIFT);
+ }
+
+ qva = (PVOID)((ULONG)qva | EISA_QVA);
+
+ return(qva);
+ }
+
+ if (PA.HighPart == 3) {
+
+ //
+ // in EISA IO space
+ //
+
+ if (VA == 0) {
+
+ PA.LowPart = PA.LowPart >> 2;
+ qva = (PVOID)(PA.QuadPart >> EISA_BIT_SHIFT-2);
+
+ } else {
+
+ qva = (PVOID)((ULONG)VA >> EISA_BIT_SHIFT);
+
+ }
+
+ qva = (PVOID)((ULONG)qva | EISA_QVA);
+
+ return(qva);
+ }
+
+ if (PA.HighPart == 1) {
+
+ //
+ // on the combo chip (82C106)
+ //
+
+ if (VA == 0) {
+
+ qva = (PVOID)(PA.QuadPart >> COMBO_BIT_SHIFT);
+
+ } else {
+
+ qva = (PVOID)((ULONG)VA >> COMBO_BIT_SHIFT);
+ }
+
+ qva = (PVOID)((ULONG)qva | COMBO_QVA);
+
+ return(qva);
+ }
+
+ //
+ // It is not an I/O space address, return the VA as the QVA
+ //
+
+ return(VA);
+
+}
+
+PVOID
+HalDereferenceQva(
+ PVOID Qva,
+ INTERFACE_TYPE InterfaceType,
+ ULONG BusNumber
+ )
+/*++
+
+Routine Description:
+
+ This function performs the inverse of the HalCreateQva for I/O addresses
+ that are memory-mapped (i.e. the quasi-virtual address was created from
+ a virtual address rather than a physical address).
+
+Arguments:
+
+ Qva - Supplies the quasi-virtual address to be converted back to a
+ virtual address.
+
+ InterfaceType - Supplies the interface type of the bus to which the
+ Qva pertains.
+
+ BusNumber - Supplies the bus number of the bus to which the Qva pertains.
+
+Return Value:
+
+ The Virtual Address from which the quasi-address was originally created
+ is returned.
+
+--*/
+{
+
+
+ //
+ // For Jensen we have only 2 buses:
+ //
+ // Internal(0)
+ // Eisa(0)
+ //
+ // We will allow Isa as an alias for Eisa. All other values not named
+ // above will be considered bogus. Bus Number must be zero.
+ //
+
+ if( BusNumber != 0 ){
+ return NULL;
+ }
+
+ switch (InterfaceType ){
+
+ case Internal:
+
+ return( (PVOID)( (ULONG)Qva << COMBO_BIT_SHIFT ) );
+
+ case Isa:
+ case Eisa:
+
+ return( (PVOID)( (ULONG)Qva << EISA_BIT_SHIFT ) );
+
+
+ default:
+
+ return NULL;
+
+ }
+
+
+}
+
+
+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 addition 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 allocatation amount to 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 thru KSEG0, since we don't want to
+ // use translation entries.
+ //
+
+ MapBufferVirtualAddress =
+ (PVOID)(HalpMapBufferPhysicalAddress.LowPart |
+ (ULONG)KSEG0_BASE);
+
+ } else {
+
+ //
+ // Allocate the map buffers.
+ //
+ physicalAddress.LowPart = MAXIMUM_ISA_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.
+ //
+
+ if (!HALP_IS_PHYSICAL_ADDRESS(MapBufferVirtualAddress)) {
+
+ MapBufferPhysicalAddress = MmGetPhysicalAddress(
+ MapBufferVirtualAddress
+ ).LowPart;
+
+ } else {
+
+ MapBufferPhysicalAddress = (ULONG)MapBufferVirtualAddress &
+ (~KSEG0_BASE);
+ }
+
+ }
+
+ //
+ // Initailize the map registers where memory has been allocated.
+ //
+
+ TranslationEntry = ((PTRANSLATION_ENTRY) AdapterObject->MapRegisterBase) +
+ AdapterObject->NumberOfMapRegisters;
+
+ for (i = 0; (ULONG) i < NumberOfPages; i++) {
+
+ //
+ // Make sure the perivous entry is physically contiguous with the next
+ // entry and that a 64K physical bountry 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 bountry.
+ //
+
+ 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
+ phyically 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 / 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 )) {
+
+ RtlZeroMemory (AdapterObject, sizeof (ADAPTER_OBJECT));
+ Status = ObInsertObject( AdapterObject,
+ NULL,
+ FILE_READ_DATA | FILE_WRITE_DATA,
+ 0,
+ (PVOID *) NULL,
+ &Handle );
+
+ if (NT_SUCCESS( Status )) {
+
+ ZwClose( 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 )),
+ ( MAXIMUM_MAP_BUFFER_SIZE / 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,
+ (MAXIMUM_MAP_BUFFER_SIZE / PAGE_SIZE) *
+ sizeof(TRANSLATION_ENTRY)
+ );
+
+ if (AdapterObject->MapRegisterBase == NULL) {
+
+ ObDereferenceObject( AdapterObject );
+ AdapterObject = NULL;
+ return(NULL);
+
+ }
+
+ //
+ // Zero the map registers.
+ //
+
+ RtlZeroMemory(
+ AdapterObject->MapRegisterBase,
+ (MAXIMUM_MAP_BUFFER_SIZE / 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
+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 = TRUE;
+
+ } 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);
+
+ }
+
+ if (AdapterObject->EisaAdapter) {
+
+ AdapterObject->MapRegisterBase = (PVOID)
+ ((ULONG) AdapterObject->MapRegisterBase | EISA_ADAPTER);
+
+ }
+ }
+
+ 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 | EISA_ADAPTER));
+
+ 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);
+
+ }
+
+ if (AdapterObject->EisaAdapter) {
+
+ AdapterObject->MapRegisterBase = (PVOID)
+ ((ULONG) AdapterObject->MapRegisterBase | EISA_ADAPTER);
+
+ }
+ //
+ // 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
+HalpCreateDmaStructures (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the structures necessary for DMA operations
+ and connects the intermediate interrupt dispatcher.
+
+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.
+
+--*/
+
+{
+
+
+ //
+ // Init the Eisa interrupts
+ //
+
+ return HalpCreateEisaStructures ();
+}
+
+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 to be used by bus masters.
+
+--*/
+
+{
+ 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;
+ BOOLEAN specialMemory;
+
+ pageOffset = BYTE_OFFSET(CurrentVa);
+
+ if ( MapRegisterBase != NULL ) {
+ specialMemory = HalpAnySpecialMemory( Mdl, *Length, pageOffset);
+ } else {
+ specialMemory = FALSE;
+ }
+
+ //
+ // 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 ( !specialMemory ) {
+ if (HalpEisaDma) {
+
+ while( transferLength < *Length ) {
+
+ if (*pageFrame + 1 != *(pageFrame + 1)) {
+ break;
+ }
+
+ transferLength += PAGE_SIZE;
+ pageFrame++;
+
+ }
+
+ } else {
+
+ while( transferLength < *Length ) {
+
+ if (*pageFrame + 1 != *(pageFrame + 1) ||
+ (*pageFrame & ~0x07) != (*(pageFrame + 1) & ~0x07)) {
+ 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 | EISA_ADAPTER));
+
+
+ if ( specialMemory ) {
+
+ logicalAddress = translationEntry->PhysicalAddress + pageOffset;
+ translationEntry->Index = HOLE_BUFFER;
+ transferLength = *Length;
+
+ //
+ // Copy the data.
+ //
+
+ if (WriteToDevice) {
+
+ HalpCopyBufferMap(
+ Mdl,
+ translationEntry,
+ CurrentVa,
+ *Length,
+ WriteToDevice
+ );
+ }
+
+
+ } else {
+
+ if (((ULONG) MapRegisterBase & NO_SCATTER_GATHER) ||
+ !((ULONG)MapRegisterBase & EISA_ADAPTER)) {
+
+ if ((ULONG) MapRegisterBase & NO_SCATTER_GATHER
+ && transferLength < *Length) {
+
+ logicalAddress = translationEntry->PhysicalAddress + pageOffset;
+ translationEntry->Index = COPY_BUFFER;
+ index = 0;
+ transferLength = *Length;
+ useBuffer = TRUE;
+
+ } else {
+
+ useBuffer = FALSE;
+ index = translationEntry->Index;
+ translationEntry->Index += ADDRESS_AND_SIZE_TO_SPAN_PAGES(
+ CurrentVa,
+ transferLength
+ );
+
+ }
+
+ //
+ // For devices with no scatter/gather or non-Eisa devices:
+ // 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_ISA_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) {
+
+ HalpCopyBufferMap(
+ Mdl,
+ translationEntry + index,
+ CurrentVa,
+ *Length,
+ WriteToDevice
+ );
+
+ }
+
+ } else {
+
+ translationEntry->Index = SKIP_BUFFER;
+
+ }
+ }
+
+ }
+
+ //
+ // 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_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 );
+
+ WRITE_PORT_UCHAR( &dmaControl->Mode, adapterMode );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseAddress,
+ bytePointer[0]
+ );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseAddress,
+ bytePointer[1]
+ );
+
+ WRITE_PORT_UCHAR(
+ ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageLowPort) +
+ (ULONG)AdapterObject->PagePort,
+ bytePointer[2]
+ );
+
+ if (HalpEisaDma) {
+
+ //
+ // 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_PORT_UCHAR(
+ ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort) +
+ (ULONG)AdapterObject->PagePort,
+ 0
+ );
+ }
+
+ //
+ // Notify DMA chip of the length to transfer.
+ //
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount,
+ (UCHAR) ((transferLength - 1) & 0xff)
+ );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount,
+ (UCHAR) ((transferLength - 1) >> 8)
+ );
+
+
+ //
+ // Set the DMA chip to read or write mode; and unmask it.
+ //
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber)
+ );
+
+ } else {
+
+ //
+ // This request is for DMA controller 2
+ //
+
+ PDMA2_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 );
+
+ WRITE_PORT_UCHAR( &dmaControl->Mode, adapterMode );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseAddress,
+ bytePointer[0]
+ );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseAddress,
+ bytePointer[1]
+ );
+
+ WRITE_PORT_UCHAR(
+ ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageLowPort) +
+ (ULONG)AdapterObject->PagePort,
+ bytePointer[2]
+ );
+
+ if (HalpEisaDma) {
+
+ //
+ // 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_PORT_UCHAR(
+ ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort) +
+ (ULONG)AdapterObject->PagePort,
+ 0
+ );
+ }
+
+ //
+ // Notify DMA chip of the length to transfer.
+ //
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount,
+ (UCHAR) ((transferLength - 1) & 0xff)
+ );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount,
+ (UCHAR) ((transferLength - 1) >> 8)
+ );
+
+
+ //
+ // Set the DMA chip to read or write mode; and unmask it.
+ //
+
+ WRITE_PORT_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 Jensen 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 - If the transfer was successful.
+
+ FALSE - If there was an error in the transfer.
+
+--*/
+{
+
+ PTRANSLATION_ENTRY translationEntry;
+ PULONG pageFrame;
+ ULONG transferLength;
+ ULONG partialLength;
+ BOOLEAN masterDevice;
+ ULONG index;
+
+ 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_PORT_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_SETMASK | AdapterObject->ChannelNumber)
+ );
+
+ } else {
+
+ //
+ // This request is for DMA controller 2
+ //
+
+ PDMA2_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_PORT_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.
+ //
+
+ //
+ // Strip no scatter/gather flag.
+ //
+
+ translationEntry = (PTRANSLATION_ENTRY) ((ULONG) MapRegisterBase &
+ ~(NO_SCATTER_GATHER | EISA_ADAPTER));
+
+ if ( translationEntry->Index == SKIP_BUFFER ) {
+ translationEntry->Index = 0;
+ return(TRUE);
+ }
+
+ if (!WriteToDevice) {
+
+ //
+ // If this is not a master device, then just transfer the buffer.
+ //
+
+ if (translationEntry->Index == HOLE_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.
+ //
+
+ HalpCopyBufferMap(
+ Mdl,
+ translationEntry,
+ CurrentVa,
+ Length,
+ WriteToDevice
+ );
+
+ } else 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.
+ //
+
+ HalpCopyBufferMap(
+ Mdl,
+ translationEntry,
+ CurrentVa,
+ Length,
+ WriteToDevice
+ );
+ }
+
+ } else if (!((ULONG) MapRegisterBase & NO_SCATTER_GATHER) &&
+ !((ULONG) MapRegisterBase & EISA_ADAPTER)) {
+
+ //
+ // Cycle through the pages of the transfer to determine if there
+ // are any which need to be copied back.
+ //
+
+ transferLength = PAGE_SIZE - BYTE_OFFSET(CurrentVa);
+ partialLength = transferLength;
+ pageFrame = (PULONG)(Mdl+1);
+ pageFrame += ((ULONG) CurrentVa - (ULONG) Mdl->StartVa) >> PAGE_SHIFT;
+
+ while( transferLength <= Length ){
+
+ if (*pageFrame >= BYTES_TO_PAGES(MAXIMUM_ISA_PHYSICAL_ADDRESS)) {
+
+ HalpCopyBufferMap(
+ Mdl,
+ translationEntry,
+ CurrentVa,
+ partialLength,
+ WriteToDevice
+ );
+
+ }
+
+ (PCCHAR) CurrentVa += partialLength;
+ partialLength = PAGE_SIZE;
+
+ //
+ // Note that transferLength indicates the amount which will
+ // be transfered after the next loop; thus, it is updated
+ // with the new partial length.
+ //
+
+ transferLength += partialLength;
+ pageFrame++;
+ translationEntry++;
+ }
+
+ //
+ // Process any remaining residue.
+ //
+
+ partialLength = Length - transferLength + partialLength;
+ if (partialLength && (*pageFrame >= BYTES_TO_PAGES(MAXIMUM_ISA_PHYSICAL_ADDRESS))) {
+
+ HalpCopyBufferMap(
+ Mdl,
+ translationEntry,
+ CurrentVa,
+ partialLength,
+ WriteToDevice
+ );
+
+ }
+ }
+ }
+
+ //
+ // Strip no scatter/gather flag.
+ //
+
+ translationEntry = (PTRANSLATION_ENTRY) ((ULONG) MapRegisterBase &
+ ~(NO_SCATTER_GATHER | EISA_ADAPTER));
+
+ //
+ // Clear index in map register.
+ //
+
+ translationEntry->Index = 0;
+
+ return TRUE;
+}
+
+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);
+}
+
+ULONG
+HalpGetEisaData (
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ 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:
+
+ BusHandler - Registered BUSHANDLER for the target configuration space
+
+ RootHandler - Registered BUSHANDLER for the orginating HalGetBusData
+ request.
+
+ 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;
+ ULONG BusNumber;
+ 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;
+
+
+ UNREFERENCED_PARAMETER( RootHandler );
+
+ 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)) {
+#if DBG
+ DbgPrint("HAL: Open Status = %x\n",NtStatus);
+#endif
+ return(0);
+ }
+
+ //
+ // Init bus number path
+ //
+
+ BusNumber = BusHandler->BusNumber;
+
+ 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)) {
+#if DBG
+ DbgPrint("HAL: Opening Bus Number: Status = %x\n",NtStatus);
+#endif
+ 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.
+ //
+
+ ValueInformation = (PKEY_VALUE_FULL_INFORMATION) &i;
+
+ NtStatus = ZwQueryValueKey(
+ BusHandle,
+ &ConfigDataName,
+ KeyValueFullInformation,
+ ValueInformation,
+ 0,
+ &BytesNeeded
+ );
+
+ KeyValueBuffer = ExAllocatePool(
+ NonPagedPool,
+ BytesNeeded
+ );
+
+ if (KeyValueBuffer == NULL) {
+#if DBG
+ DbgPrint("HAL: Cannot allocate Key Value Buffer\n");
+#endif
+ 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) {
+#if DBG
+ DbgPrint("HAL: Query Config Data: Status = %x\n",NtStatus);
+#endif
+ 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:
+
+#if DBG
+ DbgPrint("Bad Data in registry!\n");
+#endif
+
+ 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;
+}
+
+
+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_PORT_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_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 );
+
+ //
+ // Read the current DMA count.
+ //
+
+ count = READ_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount
+ );
+
+ count |= READ_PORT_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_PORT_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_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 );
+
+ //
+ // Read the current DMA count.
+ //
+
+ count = READ_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount
+ );
+
+ count |= READ_PORT_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);
+
+
+}
+
+
+BOOLEAN
+HalpSpecialMemory(
+ IN ULONG PFN
+ )
+/*++
+
+Routine Description:
+
+ This function checks if the supplied PFN is contained within a section
+ of special memory.
+
+Arguments:
+
+ PFN - Page Frame Number of the page in question.
+
+Return Value:
+
+ Returns TRUE if the specified page is part of special memory.
+
+--*/
+
+{
+ PMEMORY_REGION specialMemoryRegion = HalpSpecialRegions;
+
+ while ( specialMemoryRegion != NULL ) {
+ if ( PFN >= specialMemoryRegion->PfnBase &&
+ PFN < specialMemoryRegion->PfnBase + specialMemoryRegion->PfnCount ) {
+ return TRUE;
+ }
+ specialMemoryRegion = specialMemoryRegion->Next;
+ }
+ return FALSE;
+}
+
+
+VOID
+HalpInitializeSpecialMemory(
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ )
+
+/*++
+
+Routine Description:
+
+ This function initializes the special memory regions on Jensen.
+
+Arguments:
+
+ LoaderBlock - pointer to the Loader Parameter Block.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PLIST_ENTRY NextMd;
+ PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
+ PMEMORY_REGION MemoryRegion;
+
+ //
+ // Initialize the fixed half-meg region, length is half-meg also.
+ //
+
+ HalpHalfMeg.PfnBase = HALF_MEGABYTE / PAGE_SIZE;
+ HalpHalfMeg.PfnCount = HALF_MEGABYTE / PAGE_SIZE;
+
+ //
+ // Link the half-meg region into the special regions list
+ //
+
+ HalpHalfMeg.Next = HalpSpecialRegions;
+ HalpSpecialRegions = &HalpHalfMeg;
+
+ return;
+
+#if 0
+ //
+ // Scan through all memory descriptors looking for special memory regions
+ //
+
+ NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
+
+ while ( NextMd != &LoaderBlock->MemoryDescriptorListHead ) {
+
+ Descriptor = CONTAINING_RECORD(NextMd,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+ if ( Descriptor->MemoryType == LoaderSpecialMemory ) {
+
+ //
+ // Allocate pool and copy info into MemoryRegion and insert in list
+ //
+
+ if ( sizeof(MEMORY_REGION) > HalpMemoryRegionSize ) {
+ return;
+ }
+
+ HalpMemoryRegionSize -= sizeof(MEMORY_REGION);
+ MemoryRegion = (PMEMORY_REGION) HalpMemoryRegionBuffers;
+ HalpMemoryRegionBuffers = (PVOID) (MemoryRegion + 1);
+
+ MemoryRegion->PfnBase = Descriptor->BasePage;
+ MemoryRegion->PfnCount = Descriptor->PageCount;
+ MemoryRegion->Next = HalpSpecialRegions;
+ HalpSpecialRegions = MemoryRegion;
+ Descriptor->MemoryType = LoaderFree;
+
+ }
+
+ NextMd = NextMd->Flink;
+ }
+
+ return;
+
+#endif // 0
+
+}
+
+
+BOOLEAN
+HalpAnySpecialMemory(
+ IN PMDL Mdl,
+ IN ULONG Length,
+ IN ULONG Offset
+ )
+/*++
+
+Routine Description:
+
+ This function checks an MDL to see if any pages contained in the MDL
+ are from 'special memory'.
+
+Arguments:
+
+ Mdl - pointer to an MDL.
+
+ Length - length of requested transfer.
+
+ Offset - offset of first byte within the first page for this transfer.
+
+Return Value:
+
+ Reutrns TRUE if any of the pages in the MDL are in 'special memory',
+ otherwise returns FALSE.
+
+--*/
+
+{
+ ULONG i;
+ PULONG pageFrame;
+ ULONG numRegs;
+
+ pageFrame = (PULONG)(Mdl + 1);
+
+ // Calculate number of PFNs to scan
+
+ numRegs = (Length + Offset - 1) >> PAGE_SHIFT;
+
+ for ( i = 0; i <= numRegs; i++ ) {
+ if ( HalpSpecialMemory(*pageFrame) ) {
+ return TRUE;
+ }
+ pageFrame++;
+ }
+ return FALSE;
+}
+
+
+VOID
+HalpRegisterInternalBusHandlers (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function registers the bushandlers for buses on the system
+ that will always be present on the system.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PBUS_HANDLER Bus;
+
+ //
+ // Initalize BusHandler data before registering any handlers
+ //
+
+ HalpInitBusHandler ();
+
+ //
+ // Build the processor internal bus 0
+ //
+
+ HaliRegisterBusHandler (ProcessorInternal, // Bus Type
+ -1, // No config space
+ 0, // Bus Number
+ -1, // No parent bus type
+ 0, // No parent bus number
+ 0, // No extension data
+ NULL, // No install handler
+ &Bus); // Bushandler return
+
+ Bus->GetInterruptVector = HalpGetSystemInterruptVector;
+
+ //
+ // Build internal-bus 0, or system level bus
+ //
+
+ HaliRegisterBusHandler (Internal, // Bus Type
+ -1, // No config space
+ 0, // Bus Number
+ -1, // No parent bus type
+ 0, // No parent bus number
+ 0, // No extension data
+ NULL, // No install handler
+ &Bus); // Bushandler return
+
+ Bus->GetInterruptVector = HalpGetSystemInterruptVector;
+ Bus->TranslateBusAddress = HalpTranslateSystemBusAddress;
+
+ //
+ // Build Isa/Eisa bus #0
+ //
+
+ HaliRegisterBusHandler (Eisa, // Bus Type
+ EisaConfiguration, // Config space type
+ 0, // Internal bus #0
+ Internal, // Parent bus type
+ 0, // Parent bus number
+ 0, // No extension data
+ NULL, // No install handler
+ &Bus); // Bushandler return
+
+ Bus->GetBusData = HalpGetEisaData;
+ Bus->AdjustResourceList = HalpAdjustEisaResourceList;
+
+ HaliRegisterBusHandler (Isa, // Bus Type
+ -1, // No config space
+ 0, // Internal bus #0
+ Eisa, // Parent bus type
+ 0, // Parent bus number
+ 0, // No extension data
+ NULL, // No install handler
+ &Bus); // Bushandler returne
+
+ Bus->GetBusData = HalpNoBusData;
+ Bus->AdjustResourceList = HalpAdjustIsaResourceList;
+}
+
+NTSTATUS
+HalpAdjustIsaResourceList (
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList
+ )
+/*++
+
+Routine Description:
+
+ Takes the pResourceList and limits any requested resource to
+ it's corrisponding bus requirements.
+
+Arguments:
+
+ BusHandler - Registered BUSHANDLER for the target configuration space
+
+ RootHandler - Register BUSHANDLER for the orginating HalAdjustResourceList request.
+
+ 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;
+}
+
+
+NTSTATUS
+HalpAdjustEisaResourceList (
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList
+ )
+/*++
+
+Routine Description:
+
+ Takes the pResourceList and limits any requested resource to
+ it's corrisponding bus requirements.
+
+Arguments:
+
+ BusHandler - Registered BUSHANDLER for the target configuration space
+
+ RootHandler - Register BUSHANDLER for the orginating HalAdjustResourceList request.
+
+ 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;
+}
+#endif
diff --git a/private/ntos/nthals/hal0jens/alpha/jxinfo.c b/private/ntos/nthals/hal0jens/alpha/jxinfo.c
new file mode 100644
index 000000000..370c6198e
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/jxinfo.c
@@ -0,0 +1,142 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1994 Digital Equipment Corporation
+
+Module Name:
+
+ info.c
+
+Abstract:
+
+Author:
+
+ Ken Reneris (kenr) 08-Aug-1994
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+
+#include "halp.h"
+
+#ifdef _PNP_POWER_
+HAL_CALLBACKS HalCallback;
+#endif // _PNP_POWER_
+
+//
+// External references
+//
+
+NTSTATUS
+HalpQueryInstalledBusInformation (
+ OUT PVOID Buffer,
+ IN ULONG BufferLength,
+ OUT PULONG ReturnedLength
+ );
+
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE,HaliQuerySystemInformation)
+#pragma alloc_text(PAGE,HaliSetSystemInformation)
+#endif
+
+
+NTSTATUS
+HaliQuerySystemInformation(
+ IN HAL_QUERY_INFORMATION_CLASS InformationClass,
+ IN ULONG BufferSize,
+ OUT PVOID Buffer,
+ OUT PULONG ReturnedLength
+ )
+/*++
+
+Routine Description:
+
+ The function returns system-wide information controlled by the HAL for a
+ variety of classes.
+
+Arguments:
+
+ InformationClass - Information class of the request.
+
+ BufferSize - Size of buffer supplied by the caller.
+
+ Buffer - Supplies the space to store the data.
+
+ ReturnedLength - Supplies a count in bytes of the amount of data returned.
+
+Return Value:
+
+ STATUS_SUCCESS or error.
+
+--*/
+{
+ NTSTATUS Status;
+
+ switch (InformationClass) {
+ case HalInstalledBusInformation:
+ Status = HalpQueryInstalledBusInformation (
+ Buffer,
+ BufferSize,
+ ReturnedLength
+ );
+ break;
+
+ case HalProfileSourceInformation:
+ Status = HalpProfileSourceInformation (
+ Buffer,
+ BufferSize,
+ ReturnedLength);
+ break;
+
+ default:
+ Status = STATUS_INVALID_LEVEL;
+ break;
+ }
+
+ return(Status);
+}
+
+NTSTATUS
+HaliSetSystemInformation (
+ IN HAL_SET_INFORMATION_CLASS InformationClass,
+ IN ULONG BufferSize,
+ IN PVOID Buffer
+ )
+/*++
+
+Routine Description:
+
+ The function allows setting of various fields return by
+ HalQuerySystemInformation.
+
+Arguments:
+
+ InformationClass - Information class of the request.
+
+ BufferSize - Size of buffer supplied by the caller.
+
+ Buffer - Supplies the data to be set.
+
+Return Value:
+
+ STATUS_SUCCESS or error.
+
+--*/
+{
+ NTSTATUS Status;
+
+ switch (InformationClass) {
+
+ default:
+ Status = STATUS_INVALID_LEVEL;
+ break;
+ }
+
+ return Status;
+}
diff --git a/private/ntos/nthals/hal0jens/alpha/jxinitnt.c b/private/ntos/nthals/hal0jens/alpha/jxinitnt.c
new file mode 100644
index 000000000..e1fb48218
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/jxinitnt.c
@@ -0,0 +1,471 @@
+#if defined(JENSEN)
+
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1992 Digital Equipment Corporation
+
+Module Name:
+
+ .../ntos/hal/alpha/jxinitnt.c
+
+Abstract:
+
+
+ This module implements the interrupt initialization for an Alpha/Jensen
+ system. Contains the VLSI 82C106, the 82357 and an EISA bus.
+
+ Stolen from Dave Cutler's jxinitnt.c in ../mips
+
+Author:
+
+ David N. Cutler (davec) 26-Apr-1991
+ Jeff McLeman (DEC) 18-May-1992
+ Miche Baker-Harvey (miche) 18-May-1992
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+ Jeff McLeman (DEC) 30-Jul-1992
+ Remove Clock interrupt from this module, because it is done
+ in JXCLOCK.C
+--*/
+
+#include "halp.h"
+#include "jnsnrtc.h"
+#include "jnsndef.h"
+#include "jxserp.h"
+#include "eisa.h"
+
+
+
+//
+// Define global data for builtin device interrupt enables.
+//
+
+USHORT HalpBuiltinInterruptEnable;
+
+
+// irql mask and tables
+//
+// irql 0 - passive
+// irql 1 - sfw apc level
+// irql 2 - sfw dispatch level
+// irql 3 - device low (All devices except)
+// irql 4 - device high (the serial lines)
+// irql 5 - clock
+// irql 6 - real time
+// irql 7 - error, mchk, nmi, halt
+//
+//
+// IDT mappings:
+// For the built-ins, GetInterruptVector will need more info,
+// or it will have to be built-in to the routines, since
+// these don't match IRQL levels in any meaningful way.
+//
+// 0 passive 8
+// 1 apc 9
+// 2 dispatch 10 PIC
+// 3 11 keyboard/mouse
+// 4 serial 12 errors
+// 5 clock 13 parallel
+// 6 14 halt
+// 7 nmi 15
+//
+// This is assuming the following prioritization:
+// nmi
+// halt
+// errors
+// clock
+// serial
+// parallel
+// keyboard/mouse
+// pic
+
+//
+// This is the HalpIrqlMask for Jensen
+// Jensen interrupt pins:
+//
+// eirq 0 interval timer from 82c106
+// eirq 1 PIC - 82357 interrupts
+// eirq 2 NMI from the ISP
+// eirq 3 Keyboard and Mouse (82c106)
+// eirq 4 Front-panel HALT switch
+// eirq 5 serial ports A and B.
+// (note that the parallel printer from the 82c106 comes in on the PIC)
+
+#include "jxirql.h"
+
+//
+// For information purposes: here is what the IDT division looks like:
+//
+// 000-015 Built-ins (we only use 8 entries; NT wants 10)
+// 016-031 ISA
+// 048-063 EISA
+// 080-095 PCI
+// 112-127 Turbo Channel
+// 128-255 unused, as are all other holes
+//
+
+VOID
+HalpClearInterrupts(
+ );
+
+VOID
+HalpHaltInterrupt(
+ );
+
+
+BOOLEAN
+HalpInitializeInterrupts (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function initializes interrupts for an Alpha system.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A value of TRUE is returned if the initialization is successfully
+ completed. Otherwise a value of FALSE is returned.
+
+--*/
+
+{
+
+ UCHAR DataByte;
+ ULONG DataLong;
+ ULONG Index;
+ extern VOID KeUpdateSystemTime(VOID);
+
+ //
+ // Initialize HAL processor parameters based on estimated CPU speed.
+ // This must be done before HalpStallExecution is called. Compute integral
+ // megahertz first to avoid rounding errors due to imprecise cycle clock
+ // period values.
+ //
+
+ HalpInitializeProcessorParameters();
+
+ //
+ // Initialize the IRQL translation table in the PCR. These tables are
+ // used by the interrupt dispatcher to determine the new irql, and to
+ // determine the vector into the IDT. This is a bit different from
+ // "normal" NT, which uses the IRQL to index into the vector table directly.
+ // Since we have more information about who has interrupted (from the CPU
+ // interrupt pins), we use that information to get directly to the vector
+ // for the builting device which has interrupted.
+ //
+
+
+ for (Index = 0; Index < (sizeof(HalpIrqlMask)/4); Index++){
+ PCR->IrqlMask[Index].IrqlTableIndex = HalpIrqlMask[Index].IrqlTableIndex;
+ PCR->IrqlMask[Index].IDTIndex = HalpIrqlMask[Index].IDTIndex;
+ }
+
+ for (Index = 0; Index < (sizeof(HalpIET)/4); Index++){
+ PCR->IrqlTable[Index] = HalpIET[Index];
+ }
+
+
+
+ //
+ // Connect the Stall interrupt vector to the clock. When the
+ // profile count is calculated, we then connect the normal
+ // clock.
+
+
+ PCR->InterruptRoutine[CLOCK2_LEVEL] = HalpStallInterrupt;
+
+ //
+ // Register the Halt interrupt
+ //
+
+ PCR->InterruptRoutine[HALT_VECTOR] = (PKINTERRUPT_ROUTINE)HalpHaltInterrupt;
+
+ HalpInitializeProfiler();
+
+ //
+ // Clear all pending interrupts
+ //
+
+ HalpClearInterrupts();
+
+ //
+ // Start the peridodic interrupt from the RTC
+ //
+ HalpProgramIntervalTimer(MAXIMUM_RATE_SELECT);
+
+ //
+ // Later there must be initialization for the local interrupts
+ // and PIC, but not now ....
+
+
+ return TRUE;
+
+}
+
+
+VOID
+HalpClearInterrupts(
+ )
+/*++
+
+Routine Description:
+
+ This function clears all pending interrupts on the Jensen.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+PSP_READ_REGISTERS SP_READ;
+PSP_WRITE_REGISTERS SP_WRITE;
+UCHAR tmp;
+int i;
+UCHAR btmp;
+UCHAR DataByte;
+
+//
+// clear out VTI interrupts, except the RTC
+//
+
+#ifdef JMBUG
+ //
+ // Reset the EISA bus. This is a draconian way of clearing out any
+ // residual interrupts. It has to be done here in Phase 0, because
+ // unlike the Jazz machine, our I/O and graphics are on EISA. If we
+ // were to pull EISA reset in Phase 1, we would lose device context.
+ // Sort of like changing your sparkplugs while driving 65 MPH on
+ // interstate 5.
+
+ DataByte = 0;
+
+ ((PNMI_EXTENDED_CONTROL) &DataByte)->BusReset = 1;
+
+ WRITE_PORT_UCHAR(
+ (PUCHAR)(&((PEISA_CONTROL)DMA_VIRTUAL_BASE)->ExtendedNmiResetControl),
+ DataByte
+ );
+
+ //
+ // Use a stall loop since KeStallExecutionProcessor isn't available in
+ // Phase 0.
+ //
+
+ HalpStallExecution(4);
+
+ DataByte = 0;
+
+ WRITE_PORT_UCHAR(
+ (PUCHAR)(&((PEISA_CONTROL)DMA_VIRTUAL_BASE)->ExtendedNmiResetControl),
+ DataByte
+ );
+#endif
+
+ //
+ // COM1
+ //
+
+ //
+ // clear the interrupt enable
+ //
+
+ outVti(0x3f9, 0x0);
+ HalpStallExecution(3);
+
+ //
+ // clear out port 1 interrupts
+ //
+
+ outVti(0x3fc, 0x0f);
+ HalpStallExecution(3);
+
+ tmp = inVti(0x3fb);
+ tmp &= ~0xc0;
+ outVti(0x3fb, tmp);
+ HalpStallExecution(3);
+
+ for (i = 0; i< 15; i++) {
+ tmp = inVti(0x3f8);
+ HalpStallExecution(3);
+ if (!inVti(0x3fd) & 1) {
+ break;
+ }
+ }
+
+ for (i = 0; i< 1000; i++) {
+ if(!(0x3fe & 0x0f)) {
+ break;
+ }
+ }
+
+ for (i = 0; i< 5; i++) {
+ if (inVti(0x3fa) & 1) {
+ break;
+ }
+ }
+
+ //
+ // clear the interrupt enable
+ //
+
+ outVti(0x3f9, 0x0);
+ HalpStallExecution(3);
+ //DbgPrint("COM1: Interrupt Enable = %x\n", inVti(0x3f9));
+
+ //
+ // COM2
+ //
+
+ //
+ // clear the interrupt enable
+ //
+
+ outVti(0x2f9, 0x0);
+ HalpStallExecution(3);
+
+ //
+ // clear out port 2 interrupts
+ //
+
+ outVti(0x2fc, 0x0f);
+ HalpStallExecution(3);
+
+ tmp = inVti(0x2fb);
+ tmp &= ~0xc0;
+ outVti(0x2fb, tmp);
+ HalpStallExecution(3);
+
+ for (i = 0; i< 15; i++) {
+ tmp = inVti(0x2f8);
+ HalpStallExecution(3);
+ if (!inVti(0x2fd) & 1) {
+ break;
+ }
+ }
+
+ for (i = 0; i< 1000; i++) {
+ if(!(0x2fe & 0x0f)) {
+ break;
+ }
+ }
+
+ for (i = 0; i< 5; i++) {
+ if (inVti(0x2fa) & 1) {
+ break;
+ }
+ }
+
+ //
+ // clear the interrupt enable
+ //
+
+ outVti(0x2f9, 0x0);
+ HalpStallExecution(3);
+ //DbgPrint("COM2: Interrupt Enable = %x\n", inVti(0x2f9));
+
+ //
+ // Kbd and Mouse
+ //
+
+ outVti(0x64, 0x60);
+ HalpStallExecution(3);
+ outVti(0x60, 0x0);
+ HalpStallExecution(3);
+ tmp = inVti(0x60);
+ while (inVti(0x64) & 1) {
+ HalpStallExecution(3);
+ tmp = inVti(0x60);
+ }
+
+
+ return;
+}
+
+VOID
+HalpStallExecution(
+ ULONG Microseconds
+ )
+
+/*++
+
+Routine Description:
+
+ This function is used internally to the HAL on Alpha AXP systems to
+ stall execution before KeStallExecutionProcessor is available.
+
+Arguments:
+
+ Microseconds - Supplies the number of microseconds to stall.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ LONG StallCyclesRemaining; // signed value
+ ULONG PreviousRpcc, CurrentRpcc;
+
+
+ //
+ // Get the value of the RPCC as soon as we enter
+ //
+
+ PreviousRpcc = HalpRpcc();
+
+ //
+ // Compute the number of cycles to stall
+ //
+
+ StallCyclesRemaining = Microseconds * HalpClockMegaHertz;
+
+ //
+ // Wait while there are stall cycles remaining.
+ // The accuracy of this routine is limited by the
+ // length of this while loop.
+ //
+
+ while (StallCyclesRemaining > 0) {
+
+ CurrentRpcc = HalpRpcc();
+
+ //
+ // The subtraction always works because the Rpcc
+ // is a wrapping long-word. If it wraps, we still
+ // get the positive number we want.
+ //
+
+ StallCyclesRemaining -= (CurrentRpcc - PreviousRpcc);
+
+ //
+ // remember this RPCC value
+ //
+
+ PreviousRpcc = CurrentRpcc;
+ }
+
+}
+
+#endif
diff --git a/private/ntos/nthals/hal0jens/alpha/jxintsup.s b/private/ntos/nthals/hal0jens/alpha/jxintsup.s
new file mode 100644
index 000000000..94198c45f
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/jxintsup.s
@@ -0,0 +1,205 @@
+// TITLE("Clock and Eisa Interrupt Handlers")
+//++
+//
+// Copyright (c) 1993 Digital Equipment Corporation
+//
+// Module Name:
+//
+// jxintsup.s
+//
+// Abstract:
+//
+// This module implements the first level interrupt handlers
+// for JENSEN.
+//
+// Author:
+//
+// Joe Notarangelo 08-Jul-1993
+//
+// Environment:
+//
+// Kernel mode only.
+//
+// Revision History:
+//
+//--
+
+#include "ksalpha.h"
+#include "jnsnrtc.h"
+
+ SBTTL("System Clock Interrupt")
+//++
+//
+// VOID
+// HalpClockInterrupt(
+// )
+//
+// Routine Description:
+//
+// This function is executed for each interval timer interrupt on
+// the JENSEN. The routine is responsible for acknowledging the
+// interrupt and calling the kernel to update the system time.
+// In addition, this routine checks for breakins from the kernel debugger
+// and maintains the 64 bit performance counter based upon the
+// processor cycle counter.
+//
+// Arguments:
+//
+// TrapFrame (fp/s6) - Supplies a pointer to the trap frame for
+// the interrupt.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ .struct 0
+ .space 8 // filler for octaword alignment
+CiRa: .space 8 // space for return address
+CiFrameLength: //
+
+ NESTED_ENTRY(HalpClockInterrupt, CiFrameLength, zero )
+
+ lda sp, -CiFrameLength(sp) // allocate stack frame
+ stq ra, CiRa(sp) // save return address
+
+ PROLOGUE_END
+
+//
+// Acknowledge the clock interrupt, by reading the control register c of
+// the Real Time Clock in the 82C106 (VTI Combo Chip).
+//
+
+ ldil a0, RTC_APORT // get the address port for rtc
+ ldil a1, RTC_CONTROL_REGISTERC // address for control register
+ bsr ra, HalpWriteVti // write the address port
+
+ ldil a0, RTC_DPORT // get the data port for the rtc
+ bsr ra, HalpReadVti // read the data port
+
+//
+// Call the kernel to update the system time.
+//
+
+ ldl a1, HalpCurrentTimeIncrement
+ bis fp, zero, a0 // a0 = pointer to trap frame
+ ldl t0, __imp_KeUpdateSystemTime
+ jsr ra, (t0) // call kernel to update system time
+
+ ldl t0, HalpNextTimeIncrement // Get next time increment
+ stl t0, HalpCurrentTimeIncrement // Set CurrentTimeIncrement to NextTimeIncrement
+
+ ldl a0, HalpNextRateSelect // Get NextIntervalCount. If 0, no change required
+ beq a0, 5f
+
+ stl zero, HalpNextRateSelect // Set NextRateSelect to 0
+ bsr ra, HalpProgramIntervalTimer // Program timer with new rate select
+
+ ldl t0, HalpNewTimeIncrement // Get HalpNewTimeIncrement
+ stl t0, HalpNextTimeIncrement // Set HalpNextTimeIncrement to HalpNewTimeIncrement
+
+5:
+
+//
+// Update the 64-bit performance counter.
+//
+// N.B. - This code is careful to update the 64-bit counter atomically.
+//
+
+ lda t0, HalpRpccTime // get address of 64-bit rpcc global
+ ldq t4, 0(t0) // read rpcc global
+ rpcc t1 // read processor cycle counter
+ addl t1, zero, t1 // make t1 a longword
+ addl t4, 0, t2 // get low longword of rpcc global
+ cmpult t1, t2, t3 // is new rpcc < old rpcc
+ bne t3, 10f // if ne[true] rpcc wrapped
+ br zero, 20f // rpcc did not wrap
+
+//
+// The rpcc has wrapped, increment the high part of the 64-bit counter.
+//
+
+10:
+ lda t2, 1(zero) // t2 = 1
+ sll t2, 32, t2 // t2 = 1 0000 0000
+ addq t4, t2, t4 // increment high part by one
+
+20:
+
+ zap t4, 0x0f, t4 // clean low part of rpcc global
+ zap t1, 0xf0, t1 // clean high part of rpcc
+ addq t4, t1, t4 // merge new rpcc as low part of global
+ stq t4, 0(t0) // store the updated counter
+
+#if DEVL
+
+//
+// Check for a breakin request from the kernel debugger.
+//
+
+ ldl t0, __imp_KdPollBreakIn
+ jsr ra, (t0) // check for breakin requested
+ beq v0, 30f // if eq[false], no breakin
+ ldl t0, __imp_DbgBreakPointWithStatus
+ lda a0, DBG_STATUS_CONTROL_C
+ jsr ra, (t0) // send status to debugger
+
+30:
+
+#endif //DEVL
+
+//
+// Return to the caller.
+//
+
+ ldq ra, CiRa(sp) // restore return address
+ lda sp, CiFrameLength(sp) // deallocate stack frame
+ ret zero, (ra) // return to caller
+
+ .end HalpClockInterrupt
+
+
+ SBTTL("Eisa Interrupt")
+//++
+//
+// VOID
+// HalpEisaInterruptHandler
+// IN PKINTERRUPT Interrupt,
+// IN PVOID ServiceContext
+// )
+//
+// Routine Description:
+//
+// This function is executed as the result of an interrupt on the EISA
+// bus. The function is responsible for calling HalpEisaDispatch to
+// appropriately dispatch the EISA interrupt.
+//
+// N.B. This function exists only to capture the trap frame and forward
+// the interrupt to HalpEisaDispatch.
+//
+// Arguments:
+//
+// Interrupt (a0) - Supplies a pointer to the interrupt object.
+//
+// ServiceContext (a1) - Supplies a pointer to the service context for
+// EISA interrupts.
+//
+// TrapFrame (fp/s6) - Supplies a pointer to the trap frame for
+// the interrupt.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalpEisaInterruptHandler)
+
+ bis fp, zero, a2 // capture trap frame as argument
+ br zero, HalpEisaDispatch // dispatch the interrupt
+
+ ret zero, (ra) // will never get here
+
+ .end HalpEisaInterruptHandler
+
diff --git a/private/ntos/nthals/hal0jens/alpha/jxioacc.s b/private/ntos/nthals/hal0jens/alpha/jxioacc.s
new file mode 100644
index 000000000..1bc9b5c52
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/jxioacc.s
@@ -0,0 +1,3523 @@
+/*++
+
+Copyright (c) 1992 Digital Equipment Corporation
+
+Module Name:
+
+ jxioacc.s
+
+
+Abstract:
+
+ This contains assembler code routines for the Alpha/Jensen machine.
+
+ The module contains the functions to turn quasi virtual
+ addresses into an Alpha superpage virtual address
+ and then read or write based on the request.
+ (We are using EV4 64-bit superpage mode.)
+
+
+Author:
+
+ Rod Gamache [DEC] 19-May-1993
+ Jeff McLeman [DEC]
+ Joe Notarangelo [DEC]
+ Steve Jenness [DEC]
+
+ Completely rewrote all the ACCESS routines to use new design from
+ 14-May-1993. Work was based largely on work originally done by
+ Jeff Mcleman on 15-Jul-1992. Format of new QVA is shown below.
+
+
+Environment:
+
+ Executes in kernel mode.
+
+Revision History:
+
+
+--*/
+
+
+#include "jnsndef.h"
+#include "ksalpha.h"
+
+#define BAD_QVA 0xBADABADA
+#define BAD_LONG 1
+#define BAD_WORD 2
+#define SUPERVA 0xfffffc0000000000
+#define SUPERVA_SHORT 0xfffffc0000000020
+#define SUPERVA_LONG 0xfffffc0000000060
+
+#define HAE_PHYSICAL_BASEL 0xd0000000
+
+#define EISA_QUAD_OFFSET EISA_LONG_OFFSET*2 // To read next quadword
+#define EISA_SECOND_LONG EISA_LONG_OFFSET + EISA_LONG_LEN
+//
+// Format of QVA:
+//
+
+// +----------------------------------------------+
+// QVA: | 3 | 1 | 1 | 27 bit EISA offset |
+// +----------------------------------------------+
+// | | |
+// v | v (upper 2 bits used as HAE index)
+// KSEG1 | IO/
+// v MEM
+// EISA/
+// COMBO
+//
+// if EISA/COMBO bit: 1 is EISA space; 0 is COMBO space
+// if IO/MEM bit: 1 is IO space; 0 is MEMORY space
+//
+
+#define EISA_MEMORY -0x3fe0 // Used to generate EISA MEMORY address
+#define EISA_IO -0x3fd0 // Used to generate EISA IO address
+#define COMBO_IO -0x3ff0 // Used to generate COMBO IO address
+
+#define IO_HI_SHIFT 28 // Used with preceeding masks to form
+ // upper bits of Superpage address
+
+#define QVA_HAE_SHIFT 25 // Shift to get HAE selector bits
+
+// Mask to get selector bits (KSEG1) after HAE shift
+#define QVA_SELECTORS_SHIFTED 0x70
+
+#define QVA_ENABLE_SHIFTED 0x50 // Mask to get QVA bits after HAE shift
+
+#define EISA_BITS_ONEZERO 3*EISA_BYTE_OFFSET // mask for EISA address 1..0
+
+// Mask to clear SELECTOR bits plus EISA/COMBO and IO/MEM bits, when
+// used with LDAH this mask generates the QVA_CONTROL_FULL bit pattern plus
+// bits <63:32> are 1's. We can then cleanly pick off bits <63:25>.
+#define QVA_CONTROL -0x200
+
+// Full mask to clear SELECTOR bits plus EISA/COMBO, IO/MEM bits, and HAE bits
+#define QVA_CONTROL_FULL 0xfe000000
+
+
+
+
+ LEAF_ENTRY(READ_REGISTER_UCHAR)
+
+/*++
+
+Routine Description:
+
+ Reads a byte location in bus memory space. Since there are
+ no register buffers (RAM) in COMBO space on Jensen, we will
+ only support EISA access.
+
+
+Arguments:
+
+ a0 QVA of byte to be read.
+
+
+Return Value:
+
+ v0 Register data.
+
+--*/
+
+ srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
+ and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
+ xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
+ and a0, 3, t3 # get byte within longword
+ bne t1, 20f # br if not a bus address
+
+ ldah t0, QVA_CONTROL(zero) # get mask clear bits
+ and t2, 3, t4 # get HAE index
+ bic a0, t0, t0 # clear QVA control bits a0<63:25>
+
+ //
+ // Note - at this point we know bits t0<63:25> = 0
+ //
+ // We have already ignored the COMBO/EISA bit... we will now ignore
+ // the IO/MEM bit. This will save 2 instructions and we require that
+ // the REGISTER routines only be used for access to MEMORY space.
+ //
+
+ sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
+ ldiq t2, EISA_MEMORY # form upper bits of PA
+ sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
+ or t0, t2, t0 # generate superpage address
+
+ //
+ // Check if we have to load the HAE with a non-zero value. This
+ // is considered non-standard, but it is supported. Loading the HAE
+ // requires additional synchronization.
+ //
+ bne t4, 40f # br if HAE has to be set up
+
+ ldl v0, (t0) # get the longword
+ extbl v0, t3, v0 # get correct byte
+
+ ret zero, (ra)
+
+20:
+ //
+ // On non-I/O space access, do a normal memory operation
+ //
+ ldq_u v0, (a0) # get entire quad,don't assume aligned
+ extbl v0, a0, v0 # get the byte
+ ret zero, (ra) # return
+
+40:
+
+//
+// setup HAE.
+//
+// a0 = QVA
+// t0 = superpage address for QVA
+// t4 = HAE index
+// t3 = byte within longword
+// t2 = upper bits of EISA superpage address
+//
+ lda t1, HalpHaeTable # get address of HAE table
+ ldiq t2, COMBO_IO # form upper bits of HAE
+ addl t4, t1, t1 # get address of new HAE value
+ sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
+ ldq_u t4, (t1) # get new HAE value
+ extbl t4, t1, t4 # ...
+
+#if DBG
+ // Note: the value in t4 should never be zero!
+ beq t4, 90f # br if new HAE value is zero!
+#endif
+
+ ldiq t1, HAE_PHYSICAL_BASEL # get base address of HAE register
+ or t1, t2, t1 # generate HAE superpage address
+
+ //
+ // Raise IRQL to device level to block other accesses to EISA memory
+ //
+ ldiq a0, DEVICE_LEVEL # get device level IRQL
+ SWAP_IRQL # raise IRQL to DEVICE_LEVEL
+ bis v0, zero, a0 # save original IRQL
+
+ //
+ // We will not bother to save the original HAE value. The value
+ // in the HAE must be zero... otherwise synchronization is broken.
+ // In debug mode, we will check the HAE however.
+ //
+#if DBG
+ ldl t5, (t1) # get original HAE value
+ bne t5, 90f # br if HAE is non-zero - error!
+#endif
+
+ stl t4, (t1) # write new HAE value
+ mb # force it out
+
+ //
+ // Now we can read the byte from the EISA bus
+ //
+ ldl v0, (t0) # get the longword
+ extbl v0, t3, t4 # get correct byte
+
+ //
+ // Restore HAE before exiting
+ //
+ stl zero, (t1) # restore original HAE value
+ mb # force it out
+
+ //
+ // Lower IRQL
+ //
+ SWAP_IRQL # restore original IRQL
+ bis t4, zero, v0 # put result in v0
+
+ ret zero, (ra)
+
+#if DBG
+90:
+ // New HAE value is zero!
+ BREAK_DEBUG_STOP
+ ldil a0, BAD_QVA
+ jsr t12, KeBugCheck # crash if bad HAE index
+#endif
+
+ .end READ_REGISTER_UCHAR
+
+
+ LEAF_ENTRY(READ_REGISTER_USHORT)
+
+/*++
+
+Routine Description:
+
+ Reads a byte location in bus memory space. Since there are
+ no register buffers (RAM) in COMBO space on Jensen, we will
+ only support EISA access. Note: a0 should be word aligned.
+
+
+Arguments:
+
+ a0 QVA of word to be read.
+
+
+Return Value:
+
+ v0 Register data.
+
+
+--*/
+
+ srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
+ and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
+ xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
+ and a0, 3, t3 # get word within longword
+ bne t1, 20f # br if not a bus address
+
+ ldah t0, QVA_CONTROL(zero) # get mask clear bits
+ and t2, 3, t4 # get HAE index alone
+ bic a0, t0, t0 # clear QVA control bits a0<63:25>
+
+ //
+ // Note - at this point we know bits t0<63:25> = 0
+ //
+ // We have already ignored the COMBO/EISA bit... we will now ignore
+ // the IO/MEM bit. This will save 2 instructions and we require that
+ // the REGISTER routines only be used for access to MEMORY space.
+ //
+
+ sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
+ ldiq t2, EISA_MEMORY # form upper bits of PA
+ sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
+ or t0, t2, t0 # generate superpage address
+
+ //
+ // Check if we have to load the HAE with a non-zero value. This
+ // is considered non-standard, but it is supported. Loading the HAE
+ // requires additional synchronization.
+ //
+ bne t4, 40f # br if HAE has to be set up
+
+ ldl v0, EISA_WORD_LEN(t0) # get the word within longword
+ extwl v0, t3, v0 # get the correct word
+
+ ret zero, (ra)
+
+20:
+
+ //
+ // On non-I/O space access, do a normal memory operation
+ //
+ ldq_u v0, (a0) # get entire quad,don't assume aligned
+ extwl v0, a0, v0 # get the word
+ ret zero, (ra) # return
+
+40:
+
+//
+// setup HAE.
+//
+// a0 = QVA
+// t0 = superpage address for QVA
+// t4 = HAE index
+// t3 = word within longword
+// t2 = upper bits of superpage address
+//
+ lda t1, HalpHaeTable # get address of HAE table
+ ldiq t2, COMBO_IO # form upper bits of HAE
+ addl t4, t1, t1 # get address of new HAE value
+ sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
+ ldq_u t4, (t1) # get new HAE value
+ extbl t4, t1, t4 # ...
+
+#if DBG
+ // Note: the value in t4 should never be zero!
+ beq t4, 90f # br if new HAE value is zero!
+#endif
+
+ ldiq t1, HAE_PHYSICAL_BASEL # get base address of HAE register
+ or t1, t2, t1 # generate HAE superpage address
+
+ //
+ // Raise IRQL to device level to block other accesses to EISA memory
+ //
+ ldiq a0, DEVICE_LEVEL # get device level IRQL
+ SWAP_IRQL # raise IRQL to DEVICE_LEVEL
+ bis v0, zero, a0 # save original IRQL
+
+ //
+ // We will not bother to save the original HAE value. The value
+ // in the HAE must be zero... otherwise synchronization is broken.
+ // In debug mode, we will check the HAE however.
+ //
+#if DBG
+ ldl t5, (t1) # get original HAE value
+ bne t5, 90f # br if HAE is non-zero - error!
+#endif
+
+ stl t4, (t1) # write new HAE value
+ mb # force it out
+
+ //
+ // Now we can read the word from the EISA bus
+ //
+ ldl v0, EISA_WORD_LEN(t0) # get the word within longword
+ extwl v0, t3, t4 # get correct word
+
+ //
+ // Restore HAE before exiting
+ //
+ stl zero, (t1) # restore original HAE value
+ mb # force it out
+
+ //
+ // Lower IRQL
+ //
+ SWAP_IRQL # restore original IRQL
+ bis t4, zero, v0 # put result in v0
+
+ ret zero, (ra)
+
+#if DBG
+90:
+ // New HAE value is zero!
+ BREAK_DEBUG_STOP
+ ldil a0, BAD_QVA
+ jsr t12, KeBugCheck # crash if bad HAE index
+#endif
+
+
+ .end READ_REGISTER_USHORT
+
+ LEAF_ENTRY(READ_REGISTER_ULONG)
+
+/*++
+
+Routine Description:
+
+ Reads a longword location in bus memory space. Since there are
+ no register buffers (RAM) in COMBO space on Jensen, we will
+ only support EISA access. Note: a0 should be longword aligned.
+
+
+Arguments:
+
+ a0 QVA of longword to be read.
+
+
+
+Return Value:
+
+ v0 Register data
+
+
+--*/
+
+
+ srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
+ and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
+ xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
+ ldah t0, QVA_CONTROL(zero) # get mask clear bits
+ bne t1, 20f # br if not a bus address
+
+ and t2, 3, t4 # get HAE index
+ bic a0, t0, t0 # clear QVA control bits a0<63:25>
+
+ //
+ // Note - at this point we know bits t0<63:25> = 0
+ //
+ // We have already ignored the COMBO/EISA bit... we will now ignore
+ // the IO/MEM bit. This will save 2 instructions and we require that
+ // the REGISTER routines only be used for access to MEMORY space.
+ //
+
+ sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
+ ldiq t2, EISA_MEMORY # form upper bits of PA
+ sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
+ or t0, t2, t0 # generate superpage address
+
+ //
+ // Check if we have to load the HAE with a non-zero value. This
+ // is considered non-standard, but it is supported. Loading the HAE
+ // requires additional synchronization.
+ //
+ bne t4, 40f # br if HAE has to be set up
+
+ ldl v0, EISA_LONG_LEN(t0) # read the longword
+ ret zero, (ra)
+
+20:
+ //
+ // On non-I/O space access, do a normal memory operation
+ //
+ ldl v0, (a0) # read the longword
+ ret zero, (ra)
+
+
+40:
+
+//
+// setup HAE.
+//
+// a0 = QVA
+// t0 = superpage address for QVA
+// t4 = HAE index
+// t2 = upper bits of superpage address
+//
+ lda t1, HalpHaeTable # get address of HAE table
+ ldiq t2, COMBO_IO # form upper bits of HAE
+ addl t4, t1, t1 # get address of new HAE value
+ sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
+ ldq_u t4, (t1) # get new HAE value
+ extbl t4, t1, t4 # ...
+
+#if DBG
+ // Note: the value in t4 should never be zero!
+ beq t4, 90f # br if new HAE value is zero!
+#endif
+
+ ldiq t1, HAE_PHYSICAL_BASEL # get base address of HAE register
+ or t1, t2, t1 # generate HAE superpage address
+
+ //
+ // Raise IRQL to device level to block other accesses to EISA memory
+ //
+ ldiq a0, DEVICE_LEVEL # get device level IRQL
+ SWAP_IRQL # raise IRQL to DEVICE_LEVEL
+ bis v0, zero, a0 # save original IRQL
+
+ //
+ // We will not bother to save the original HAE value. The value
+ // in the HAE must be zero... otherwise synchronization is broken.
+ // In debug mode, we will check the HAE however.
+ //
+#if DBG
+ ldl t5, (t1) # get original HAE value
+ bne t5, 90f # br if HAE is non-zero - error!
+#endif
+
+ stl t4, (t1) # write new HAE value
+ mb # force it out
+
+ //
+ // Now we can read the longword from the EISA bus
+ //
+ ldl t4, EISA_LONG_LEN(t0) # read the longword
+
+ //
+ // Restore HAE before exiting
+ //
+ stl zero, (t1) # restore original HAE value
+ mb # force it out
+
+ //
+ // Lower IRQL
+ //
+ SWAP_IRQL # restore original IRQL
+ bis t4, zero, v0 # put result in v0
+
+ ret zero, (ra)
+
+#if DBG
+90:
+ // New HAE value is zero!
+ BREAK_DEBUG_STOP
+ ldil a0, BAD_QVA
+ jsr t12, KeBugCheck # crash if bad HAE index
+#endif
+//
+// HAE has to be set up... this requires a lot of extra work!
+//
+ ret zero, (ra)
+
+
+ .end READ_REGISTER_ULONG
+
+
+ LEAF_ENTRY(WRITE_REGISTER_UCHAR)
+
+/*++
+
+Routine Description:
+
+ Writes a byte location in bus memory space. Since there are no
+ register buffers (RAM) in COMBO space on Jensen, we will only
+ support access to EISA space.
+
+
+Arguments:
+
+ a0 QVA of byte to be written.
+ a1 Byte Datum to be written.
+
+Return Value:
+
+ v0 Register data.
+
+--*/
+
+ srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
+ and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
+ xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
+ and a0, 3, t3 # get byte within longword
+ bne t1, 20f # br if not a bus address
+
+ ldah t0, QVA_CONTROL(zero) # get mask clear bits
+ and t2, 3, t4 # get HAE index alone
+ bic a0, t0, t0 # clear QVA control bits a0<63:25>
+
+ //
+ // Note - at this point we know bits t0<63:25> = 0
+ //
+ // We have already ignored the COMBO/EISA bit... we will now ignore
+ // the IO/MEM bit. This will save 2 instructions and we require that
+ // the REGISTER routines only be used for access to MEMORY space.
+ //
+
+ sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
+ ldiq t2, EISA_MEMORY # form upper bits of PA
+ insbl a1, t3, t3 # put byte in correct position
+ sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
+ or t0, t2, t0 # generate superpage address
+
+ //
+ // Check if we have to load the HAE with a non-zero value. This
+ // is considered non-standard, but it is supported. Loading the HAE
+ // requires additional synchronization.
+ //
+ bne t4, 40f # br if HAE has to be set up
+
+ stl t3, (t0) # write the byte
+ mb # order the write
+ ret zero, (ra)
+
+20:
+ //
+ // If a non I/O space address, do normal memory operations
+ //
+ ldq_u t0, (a0) # get the quad
+ mskbl t0, a0, t0 # mask the proper byte
+ insbl a1, a0, t1 # put byte into position
+ bis t1, t0, t0 # merge byte in result
+ stq_u t0, (a0) # store the result
+ ret zero, (ra)
+
+40:
+
+//
+// setup HAE.
+//
+// a0 = QVA
+// t0 = superpage address for QVA
+// t4 = HAE index
+// t3 = data to be written (already put into correct lane position)
+// t2 = upper bits of superpage address
+//
+ lda t1, HalpHaeTable # get address of HAE table
+ ldiq t2, COMBO_IO # form upper bits of HAE
+ addl t4, t1, t1 # get address of new HAE value
+ sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
+ ldq_u t4, (t1) # get new HAE value
+ extbl t4, t1, t4 # ...
+
+#if DBG
+ // Note: the value in t4 should never be zero!
+ beq t4, 90f # br if new HAE value is zero!
+#endif
+
+ ldiq t1, HAE_PHYSICAL_BASEL # get base address of HAE register
+ or t1, t2, t1 # generate HAE superpage address
+
+ //
+ // Raise IRQL to device level to block other accesses to EISA memory
+ //
+ ldiq a0, DEVICE_LEVEL # get device level IRQL
+ SWAP_IRQL # raise IRQL to DEVICE_LEVEL
+ bis v0, zero, a0 # save original IRQL
+
+ //
+ // We will not bother to save the original HAE value. The value
+ // in the HAE must be zero... otherwise synchronization is broken.
+ // In debug mode, we will check the HAE however.
+ //
+#if DBG
+ ldl t5, (t1) # get original HAE value
+ bne t5, 90f # br if HAE is non-zero - error!
+#endif
+
+ stl t4, (t1) # write new HAE value
+ mb # force it out
+
+ //
+ // Now we can write the byte to the EISA bus
+ //
+ stl t3, (t0) # put byte out on bus
+ //mb # order the writes, we rely on
+ # the fact that EV4 will not reorder
+ # writes, but only merge writes. The
+ # next mb below will handle our flush.
+
+ //
+ // Restore HAE before exiting
+ //
+ stl zero, (t1) # restore original HAE value
+ mb # force it out
+
+ //
+ // Lower IRQL
+ //
+ SWAP_IRQL # restore original IRQL
+
+ ret zero, (ra)
+
+#if DBG
+90:
+ // New HAE value is zero!
+ BREAK_DEBUG_STOP
+ ldil a0, BAD_QVA
+ jsr t12, KeBugCheck # crash if bad HAE index
+#endif
+
+ .end WRITE_REGISTER_UCHAR
+
+ LEAF_ENTRY(WRITE_REGISTER_USHORT)
+
+/*++
+
+Routine Description:
+
+ Writes a word location in bus memory space. Since there are no
+ register buffers (RAM) in COMBO space on Jensen, we will only
+ support access to EISA space. Note: a0 should be word aligned.
+
+
+Arguments:
+
+ a0 QVA of word to be written.
+ a1 Word Datum to be written
+
+
+Return Value:
+
+ v0 Register data.
+
+
+--*/
+
+
+ srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
+ and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
+ xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
+ and a0, 3, t3 # get byte within longword
+ bne t1, 20f # br if not a bus address
+
+ ldah t0, QVA_CONTROL(zero) # get mask clear bits
+ and t2, 3, t4 # get HAE index
+ bic a0, t0, t0 # clear QVA control bits a0<63:25>
+
+ //
+ // Note - at this point we know bits t0<63:25> = 0
+ //
+ // We have already ignored the COMBO/EISA bit... we will now ignore
+ // the IO/MEM bit. This will save 2 instructions and we require that
+ // the REGISTER routines only be used for access to MEMORY space.
+ //
+
+ sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
+ ldiq t2, EISA_MEMORY # form upper bits of PA
+ inswl a1, t3, t3 # put the word into correct place
+ sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
+ or t0, t2, t0 # generate superpage address
+
+ //
+ // Check if we have to load the HAE with a non-zero value. This
+ // is considered non-standard, but it is supported. Loading the HAE
+ // requires additional synchronization.
+ //
+ bne t4, 40f # br if HAE has to be set up
+
+ stl t3, EISA_WORD_LEN(t0) # write the word
+ mb # order the write
+ ret zero, (ra)
+
+20:
+ //
+ // If a non I/O space address, do normal memory operations
+ //
+ ldq_u t0, (a0) # get the quad
+ mskwl t0, a0, t0 # mask the proper word
+ inswl a1, a0, t1 # put word into position
+ bis t0, t1, t0 # merge in result
+ stq_u t0, (a0) # store the result
+ ret zero, (ra)
+
+
+40:
+
+//
+// setup HAE.
+//
+// a0 = QVA
+// t0 = superpage address for QVA
+// t4 = HAE index
+// t3 = data to be written (already put into correct lane position)
+// t2 = upper bits of superpage address
+//
+ lda t1, HalpHaeTable # get address of HAE table
+ ldiq t2, COMBO_IO # form upper bits of HAE
+ addl t4, t1, t1 # get address of new HAE value
+ sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
+ ldq_u t4, (t1) # get new HAE value
+ extbl t4, t1, t4 # ...
+
+#if DBG
+ // Note: the value in t4 should never be zero!
+ beq t4, 90f # br if new HAE value is zero!
+#endif
+
+ ldiq t1, HAE_PHYSICAL_BASEL # get base address of HAE register
+ or t1, t2, t1 # generate HAE superpage address
+
+ //
+ // Raise IRQL to device level to block other accesses to EISA memory
+ //
+ ldiq a0, DEVICE_LEVEL # get device level IRQL
+ SWAP_IRQL # raise IRQL to DEVICE_LEVEL
+ bis v0, zero, a0 # save original IRQL
+
+ //
+ // We will not bother to save the original HAE value. The value
+ // in the HAE must be zero... otherwise synchronization is broken.
+ // In debug mode, we will check the HAE however.
+ //
+#if DBG
+ ldl t5, (t1) # get original HAE value
+ bne t5, 90f # br if HAE is non-zero - error!
+#endif
+
+ stl t4, (t1) # write new HAE value
+ mb # force it out
+
+ //
+ // Now we can write the word to the EISA bus
+ //
+ stl t3, EISA_WORD_LEN(t0) # write the word
+ //mb # order the writes, we rely on
+ # the fact that EV4 will not reorder
+ # writes, but only merge writes. The
+ # next mb below will handle our flush.
+
+ //
+ // Restore HAE before exiting
+ //
+ stl zero, (t1) # restore original HAE value
+ mb # force it out
+
+ //
+ // Lower IRQL
+ //
+ SWAP_IRQL # restore original IRQL
+
+ ret zero, (ra)
+
+#if DBG
+90:
+ // New HAE value is zero!
+ BREAK_DEBUG_STOP
+ ldil a0, BAD_QVA
+ jsr t12, KeBugCheck # crash if bad HAE index
+#endif
+
+
+ .end WRITE_REGISTER_USHORT
+
+ LEAF_ENTRY(WRITE_REGISTER_ULONG)
+
+/*++
+
+Routine Description:
+
+ Writes a longword location in bus memory space. Since there are no
+ register buffers (RAM) in COMBO space on Jensen, we will only
+ support access to EISA space. Note: a0 should be longword aligned.
+
+
+Arguments:
+
+ a0 QVA of longword to be written.
+ a1 Longword to be written.
+
+
+Return Value:
+
+ v0 Register data
+
+
+--*/
+
+ srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
+ and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
+ xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
+ ldah t0, QVA_CONTROL(zero) # get mask clear bits
+ bne t1, 20f # br if not a bus address
+
+ and t2, 3, t4 # get HAE index
+ bic a0, t0, t0 # clear QVA control bits a0<63:25>
+
+ //
+ // Note - at this point we know bits t0<63:25> = 0
+ //
+ // We have already ignored the COMBO/EISA bit... we will now ignore
+ // the IO/MEM bit. This will save 2 instructions and we require that
+ // the REGISTER routines only be used for access to MEMORY space.
+ //
+
+ sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
+ ldiq t2, EISA_MEMORY # form upper bits of PA
+ sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
+ or t0, t2, t0 # generate superpage address
+
+ //
+ // Check if we have to load the HAE with a non-zero value. This
+ // is considered non-standard, but it is supported. Loading the HAE
+ // requires additional synchronization.
+ //
+ bne t4, 40f # br if HAE has to be set up
+
+ stl a1, EISA_LONG_LEN(t0) # write the longword
+ mb # order the write
+ ret zero, (ra)
+
+20:
+ //
+ // On non-I/O space access, do a normal memory operation
+ //
+ stl a1, (a0) # store the longword
+ ret zero, (ra)
+
+40:
+
+//
+// setup HAE.
+//
+// a0 = QVA
+// a1 = data to be written
+// t0 = superpage address for QVA
+// t4 = HAE index
+// t2 = upper bits of superpage address
+//
+ bis a1, zero, t3 # move data to safe register
+ lda t1, HalpHaeTable # get address of HAE table
+ ldiq t2, COMBO_IO # form upper bits of HAE
+ addl t4, t1, t1 # get address of new HAE value
+ sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
+ ldq_u t4, (t1) # get new HAE value
+ extbl t4, t1, t4 # ...
+
+#if DBG
+ // Note: the value in t4 should never be zero!
+ beq t4, 90f # br if new HAE value is zero!
+#endif
+
+ ldiq t1, HAE_PHYSICAL_BASEL # get base address of HAE register
+ or t1, t2, t1 # generate HAE superpage address
+
+ //
+ // Raise IRQL to device level to block other accesses to EISA memory
+ //
+ ldiq a0, DEVICE_LEVEL # get device level IRQL
+ SWAP_IRQL # raise IRQL to DEVICE_LEVEL
+ bis v0, zero, a0 # save original IRQL
+
+ //
+ // We will not bother to save the original HAE value. The value
+ // in the HAE must be zero... otherwise synchronization is broken.
+ // In debug mode, we will check the HAE however.
+ //
+#if DBG
+ ldl t5, (t1) # get original HAE value
+ bne t5, 90f # br if HAE is non-zero - error!
+#endif
+
+ stl t4, (t1) # write new HAE value
+ mb # force it out
+
+ //
+ // Now we can write the data to the EISA bus
+ //
+ stl t3, EISA_LONG_LEN(t0) # write the longword
+ //mb # order the writes, we rely on
+ # the fact that EV4 will not reorder
+ # writes, but only merge writes. The
+ # next mb below will handle our flush.
+
+ //
+ // Restore HAE before exiting
+ //
+ stl zero, (t1) # restore original HAE value
+ mb # force it out
+
+ //
+ // Lower IRQL
+ //
+ SWAP_IRQL # restore original IRQL
+
+ ret zero, (ra)
+
+#if DBG
+90:
+ // New HAE value is zero!
+ BREAK_DEBUG_STOP
+ ldil a0, BAD_QVA
+ jsr t12, KeBugCheck # crash if bad HAE index
+#endif
+
+
+ .end WRITE_REGISTER_ULONG
+
+
+ LEAF_ENTRY(READ_PORT_UCHAR)
+
+/*++
+
+Routine Description:
+
+ Reads a byte location in I/O space. Unlike the _REGISTER_ routines,
+ these routines do not support access to main memory. This routine
+ supports both EISA IO and COMBO space.
+
+
+Arguments:
+
+ a0 QVA of byte to be read.
+
+
+Return Value:
+
+ v0 Register data.
+
+--*/
+
+#if DBG
+ srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
+ and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
+ xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
+ bne t1, 40f # br if not a bus address - error
+ and t2, 3, t4 # get HAE index
+
+ //
+ // Check if HAE is non-zero. For IO space access this should never
+ // be non-zero!
+ //
+ bne t4, 40f # br if HAE non-zero - error
+#endif
+
+ ldah t0, QVA_CONTROL(zero) # get mask clear bits
+ s8addl a0, zero, t2 # get COMBO/EISA bit in sign bit
+ bic a0, t0, t0 # clear QVA control bits a0<63:25>
+ bge t2, 20f # br if COMBO address
+
+ //
+ // EISA address
+ //
+
+ //
+ // Note - at this point we know bits t0<63:25> = 0
+ //
+ // We will now ignore the IO/MEM bit and generate bits PA<63:32>
+ // knowing that we are in EISA IO space. This will save 2 instructions
+ // and require that the PORT routines only be used for access to IO
+ // space.
+ //
+
+ ldiq t4, EISA_IO # form upper bits of PA
+ sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
+ sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
+ or t0, t4, t0 # generate superpage address
+ and a0, 3, t3 # get byte within longword
+ ldl v0, (t0) # get the longword
+ extbl v0, t3, v0 # get correct byte
+
+ ret zero, (ra)
+
+20:
+ //
+ // COMBO address
+ //
+
+ //
+ // We will now ignore the IO/MEM bit and generate bits PA<63:32>
+ // knowing that we are in COMBO IO space. This will save 2 instructions
+ // and require that the PORT routines only be used for access to IO
+ // space.
+ //
+ ldiq t4, COMBO_IO # form upper bits of PA
+ sll t0, COMBO_BIT_SHIFT, t0 # shift for combo
+ sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
+ or t0, t4, t0 # generate superpage address
+ ldl v0, (t0) # get the longword
+ //
+ // Our C compiler expects returned UCHAR values to be zero-extended.
+ //
+ zapnot v0, 1, v0
+
+ ret zero, (ra)
+
+#if DBG
+40:
+ //
+ // HAE is non-zero or not a bus address, this should never happen!
+ //
+ BREAK_DEBUG_STOP
+ or a0, zero, a2 # save bad address in a2
+ ldil a0, BAD_QVA
+ jsr t12, KeBugCheck # crash if illegal access
+#endif
+
+
+ .end READ_PORT_UCHAR
+
+ LEAF_ENTRY(READ_PORT_USHORT)
+
+/*++
+
+Routine Description:
+
+ Reads a word location from I/O space. Since during a triple boot,
+ and at other times, drivers may probe for the existence of PORTs on
+ any bus, we must support all modes of access, even though the COMBO
+ space does not have any SHORT PORTs. Note: a0 should be word aligned.
+
+
+Arguments:
+
+ a0 QVA of word to be read.
+
+
+Return Value:
+
+ v0 Register data.
+
+
+--*/
+
+
+#if DBG
+ srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
+ and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
+ xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
+ bne t1, 40f # br if not a bus address - error
+ and t2, 3, t4 # get HAE index
+
+ //
+ // Check if HAE is non-zero. For IO space access this should never
+ // be non-zero!
+ //
+ bne t4, 40f # br if HAE non-zero - error
+#endif
+
+ ldah t0, QVA_CONTROL(zero) # get mask clear bits
+ s8addl a0, zero, t2 # get COMBO/EISA bit in sign bit
+ bic a0, t0, t0 # clear QVA control bits a0<63:25>
+ bge t2, 20f # br if COMBO address
+
+ //
+ // EISA address
+ //
+
+ //
+ // Note - at this point we know bits t0<63:25> = 0
+ //
+ // We will now ignore the IO/MEM bit and generate bits PA<63:32>
+ // knowing that we are in EISA IO space. This will save 2 instructions
+ // and require that the PORT routines only be used for access to IO
+ // space.
+ //
+
+ ldiq t4, EISA_IO # form upper bits of PA
+ sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
+ sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
+ or t0, t4, t0 # generate superpage address
+ and a0, 3, t3 # get byte within longword
+ ldl v0, EISA_WORD_LEN(t0) # get the word within longword
+ extwl v0, t3, v0 # get correct word
+ ret zero, (ra)
+
+20:
+ //
+ // COMBO Address
+ //
+ //
+ // We will now ignore the IO/MEM bit and generate bits PA<63:32>
+ // knowing that we are in COMBO IO space. This will save 2 instructions
+ // and require that the PORT routines only be used for access to IO
+ // space.
+ //
+
+ ldiq t4, COMBO_IO # form upper bits of PA
+ sll t0, COMBO_BIT_SHIFT, t0 # t0 contains PA<31:0>
+ sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
+ or t0, t4, t0 # generate superpage address
+ ldl v0, (t0) # get the longword
+ //
+ // Our C compiler expects returned USHORT values to be zero-extended.
+ //
+ zapnot v0, 3, v0 # clear all but low 2 bytes
+
+ ret zero, (ra)
+
+#if DBG
+40:
+ //
+ // HAE is non-zero or not a bus address, this should never happen!
+ //
+ BREAK_DEBUG_STOP
+ or a0, zero, a2 # save bad address in a2
+ ldil a0, BAD_QVA
+ jsr t12, KeBugCheck # crash if illegal access
+#endif
+
+
+ .end READ_PORT_USHORT
+
+ LEAF_ENTRY(READ_PORT_ULONG)
+
+/*++
+
+Routine Description:
+
+ Reads a longword location from I/O space. Since during a triple boot,
+ and at other times, drivers may probe for the existence of PORTs on
+ any bus, we must support all modes of access, even though the COMBO
+ space does not have any LONG PORTs. Note: a0 should be longword aligned.
+
+
+Arguments:
+
+ a0 QVA of longword to be read.
+
+
+
+Return Value:
+
+ v0 Register data
+
+
+--*/
+
+
+#if DBG
+ srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
+ and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
+ xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
+ bne t1, 40f # br if not a bus address - error
+ and t2, 3, t4 # get HAE index
+
+ //
+ // Check if HAE is non-zero. For IO space access this should never
+ // be non-zero!
+ //
+ bne t4, 40f # br if HAE non-zero - error
+#endif
+
+ ldah t0, QVA_CONTROL(zero) # get mask clear bits
+ s8addl a0, zero, t2 # get COMBO/EISA bit in sign bit
+ bic a0, t0, t0 # clear QVA control bits a0<63:25>
+ bge t2, 20f # br if COMBO address - error
+
+ //
+ // Note - at this point we know bits t0<63:25> = 0
+ //
+ // We will now ignore the IO/MEM bit and generate bits PA<63:32>
+ // knowing that we are in EISA IO space. This will save 2 instructions
+ // and require that the PORT routines only be used for access to IO
+ // space.
+ //
+
+ ldiq t4, EISA_IO # form upper bits of PA
+ sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
+ sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
+ or t0, t4, t0 # generate superpage address
+ ldl v0, EISA_LONG_LEN(t0) # get the longword
+ ret zero, (ra)
+
+20:
+ //
+ // COMBO Address
+ //
+ //
+ // We will now ignore the IO/MEM bit and generate bits PA<63:32>
+ // knowing that we are in COMBO IO space. This will save 2 instructions
+ // and require that the PORT routines only be used for access to IO
+ // space.
+ //
+
+ ldiq t4, COMBO_IO # form upper bits of PA
+ sll t0, COMBO_BIT_SHIFT, t0 # t0 contains PA<31:0>
+ sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
+ or t0, t4, t0 # generate superpage address
+ ldl v0, (t0) # get the longword
+
+ ret zero, (ra)
+
+#if DBG
+40:
+ //
+ // HAE is non-zero or not a bus address, this should never happen!
+ //
+ BREAK_DEBUG_STOP
+ or a0, zero, a2 # save bad address in a2
+ ldil a0, BAD_QVA
+ jsr t12, KeBugCheck # crash if illegal access
+#endif
+
+
+ .end READ_PORT_ULONG
+
+
+ LEAF_ENTRY(WRITE_PORT_UCHAR)
+
+/*++
+
+Routine Description:
+
+ Writes a byte location in I/O space. Unlike the _REGISTER_ routines,
+ these routines do not support access to main memory. This routine
+ supports both EISA IO and COMBO space.
+
+
+Arguments:
+
+ a0 QVA of byte to be written.
+ a1 Byte Datum to be written.
+
+Return Value:
+
+ v0 Register data.
+
+--*/
+
+#if DBG
+ srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
+ and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
+ xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
+ bne t1, 40f # br if not a bus address - error
+ and t2, 3, t4 # get HAE index
+
+ //
+ // Check if HAE is non-zero. For IO space access this should never
+ // be non-zero!
+ //
+ bne t4, 40f # br if HAE non-zero - error
+#endif
+
+ ldah t0, QVA_CONTROL(zero) # get mask clear bits
+ s8addl a0, zero, t2 # get COMBO/EISA bit in sign bit
+ bic a0, t0, t0 # clear QVA control bits a0<63:25>
+ bge t2, 20f # br if COMBO address
+
+ //
+ // EISA address
+ //
+
+ //
+ // Note - at this point we know bits t0<63:25> = 0
+ //
+ // We will now ignore the IO/MEM bit and generate bits PA<63:32>
+ // knowing that we are in EISA IO space. This will save 2 instructions
+ // and require that the PORT routines only be used for access to IO
+ // space.
+ //
+
+ ldiq t4, EISA_IO # form upper bits of PA
+ sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
+ sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
+ and a0, 3, t3 # get byte within longword
+ or t0, t4, t0 # generate superpage address
+ insbl a1, t3, t1 # put the byte in the correct position
+ stl t1, (t0) # write the byte
+ mb # order the writes
+
+ ret zero, (ra)
+
+20:
+ //
+ // COMBO address
+ //
+
+ //
+ // We will now ignore the IO/MEM bit and generate bits PA<63:32>
+ // knowing that we are in COMBO IO space. This will save 2 instructions
+ // and require that the PORT routines only be used for access to IO
+ // space.
+ //
+ ldiq t4, COMBO_IO # form upper bits of PA
+ sll t0, COMBO_BIT_SHIFT, t0 # shift for combo
+ sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
+ or t0, t4, t0 # generate superpage address
+ stl a1, (t0) # write the byte
+ mb # order the writes
+
+ ret zero, (ra)
+
+#if DBG
+40:
+ //
+ // HAE is non-zero or not a bus address, this should never happen!
+ //
+ BREAK_DEBUG_STOP
+ or a0, zero, a2 # save bad address in a2
+ ldil a0, BAD_QVA
+ jsr t12, KeBugCheck # crash if illegal access
+#endif
+
+
+ .end WRITE_PORT_UCHAR
+
+ LEAF_ENTRY(WRITE_PORT_USHORT)
+
+/*++
+
+Routine Description:
+
+ Writes a word location in I/O space. Since during a triple boot,
+ and at other times, drivers may probe for the existence of PORTs on
+ any bus, we must support all modes of access, even though the COMBO
+ space does not have any SHORT PORTs. Note: a0 should be word aligned.
+
+
+Arguments:
+
+ a0 QVA of word to be written.
+ a1 Word Datum to be written
+
+
+Return Value:
+
+ v0 Register data.
+
+--*/
+
+
+#if DBG
+ srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
+ and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
+ xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
+ bne t1, 40f # br if not a bus address - error
+ and t2, 3, t4 # get HAE index
+
+ //
+ // Check if HAE is non-zero. For IO space access this should never
+ // be non-zero!
+ //
+ bne t4, 40f # br if HAE non-zero - error
+#endif
+
+ ldah t0, QVA_CONTROL(zero) # get mask clear bits
+ s8addl a0, zero, t2 # get COMBO/EISA bit in sign bit
+ bic a0, t0, t0 # clear QVA control bits a0<63:25>
+ bge t2, 20f # br if COMBO address - error
+
+ //
+ // Note - at this point we know bits t0<63:25> = 0
+ //
+ // We will now ignore the IO/MEM bit and generate bits PA<63:32>
+ // knowing that we are in EISA IO space. This will save 2 instructions
+ // and require that the PORT routines only be used for access to IO
+ // space.
+ //
+
+ ldiq t4, EISA_IO # form upper bits of PA
+ sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
+ sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
+ and a0, 3, t3 # get word within longword
+ or t0, t4, t0 # generate superpage address
+ inswl a1, t3, t1 # put the byte in the correct position
+ stl t1, EISA_WORD_LEN(t0) # write the word
+ mb # order the writes
+
+ ret zero, (ra)
+
+20:
+ //
+ // COMBO address
+ //
+ // We will now ignore the IO/MEM bit and generate bits PA<63:32>
+ // knowing that we are in COMBO IO space. This will save 2 instructions
+ // and require that the PORT routines only be used for access to IO
+ // space.
+ //
+
+ ldiq t4, COMBO_IO # form upper bits of PA
+ sll t0, COMBO_BIT_SHIFT, t0 # shift for combo
+ sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
+ or t0, t4, t0 # generate superpage address
+ stl a1, (t0) # write the byte
+ mb # order the writes
+
+ ret zero, (ra)
+
+#if DBG
+40:
+ //
+ // HAE is non-zero or not a bus address, this should never happen!
+ //
+ BREAK_DEBUG_STOP
+ or a0, zero, a2 # save bad address in a2
+ ldil a0, BAD_QVA
+ jsr t12, KeBugCheck # crash if illegal access
+#endif
+
+
+ .end WRITE_PORT_USHORT
+
+ LEAF_ENTRY(WRITE_PORT_ULONG)
+
+/*++
+
+Routine Description:
+
+ Writes a longword location in I/O space. Since during a triple boot
+ and at other times, drivers may probe for the existence of PORTs on
+ any bus, we must support all modes of access, even though the COMBO
+ space does not have any LONG PORTs. Note: a0 should be longword
+ aligned.
+
+
+Arguments:
+
+ a0 QVA of longword to be written.
+ a1 Longword to be written.
+
+
+Return Value:
+
+ v0 Register data
+
+
+--*/
+
+
+#if DBG
+ srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
+ and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
+ xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
+ bne t1, 40f # br if not a bus address - error
+ and t2, 3, t4 # get HAE index
+
+ //
+ // Check if HAE is non-zero. For IO space access this should never
+ // be non-zero!
+ //
+ bne t4, 40f # br if HAE non-zero - error
+#endif
+
+ ldah t0, QVA_CONTROL(zero) # get mask clear bits
+ s8addl a0, zero, t2 # get COMBO/EISA bit in sign bit
+ bic a0, t0, t0 # clear QVA control bits a0<63:25>
+ bge t2, 20f # br if COMBO address - error
+
+ //
+ // Note - at this point we know bits t0<63:25> = 0
+ //
+ // We will now ignore the IO/MEM bit and generate bits PA<63:32>
+ // knowing that we are in EISA IO space. This will save 2 instructions
+ // and require that the PORT routines only be used for access to IO
+ // space.
+ //
+
+ ldiq t4, EISA_IO # form upper bits of PA
+ sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
+ sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
+ or t0, t4, t0 # generate superpage address
+ stl a1, EISA_LONG_LEN(t0) # write the longword
+ mb # order the writes
+
+ ret zero, (ra)
+
+20:
+ //
+ // COMBO address
+ //
+ // We will now ignore the IO/MEM bit and generate bits PA<63:32>
+ // knowing that we are in COMBO IO space. This will save 2 instructions
+ // and require that the PORT routines only be used for access to IO
+ // space.
+ //
+
+ ldiq t4, COMBO_IO # form upper bits of PA
+ sll t0, COMBO_BIT_SHIFT, t0 # shift for combo
+ sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
+ or t0, t4, t0 # generate superpage address
+ stl a1, (t0) # write the byte
+ mb # order the writes
+
+ ret zero, (ra)
+
+#if DBG
+40:
+ //
+ // HAE is non-zero or not a bus address, this should never happen!
+ //
+ BREAK_DEBUG_STOP
+ or a0, zero, a2 # save bad address in a2
+ ldil a0, BAD_QVA
+ jsr t12, KeBugCheck # crash if illegal access
+#endif
+
+
+ .end WRITE_PORT_ULONG
+
+ LEAF_ENTRY(READ_PORT_BUFFER_UCHAR)
+
+/*++
+
+Routine Description:
+
+ Reads from the specified port buffer address. Since there are no
+ PORT buffers on Jensen, there is no code to handle COMBO space in
+ this routine.
+
+
+Arguments:
+
+ a0 QVA of source port.
+ a1 VA of destination buffer in memory.
+ a2 Number of bytes to move (Count).
+
+
+Return Value:
+
+ None
+
+--*/
+
+#if DBG
+ srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
+ and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
+ xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
+ bne t1, 40f # br if not a bus address - error
+ and t2, 3, t4 # get HAE index
+
+ //
+ // Check if HAE is non-zero. For IO space access this should never
+ // be non-zero!
+ //
+ bne t4, 40f # br if HAE non-zero - error
+#endif
+
+ beq a2, 30f # leave now if nothing to move
+ ldah t0, QVA_CONTROL(zero) # get mask clear bits
+ bic a0, t0, t0 # clear QVA control bits a0<63:25>
+
+ //
+ // Note - at this point we know bits t0<63:25> = 0
+ //
+ // We will now ignore the IO/MEM bit and generate bits PA<63:32>
+ // knowing that we are in EISA IO space. This will save 2 instructions
+ // and require that the PORT routines only be used for access to IO
+ // space.
+ //
+ ldiq t4, EISA_IO # form upper bits of PA
+ sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
+ sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
+ or t0, t4, t0 # generate superpage address
+ and a0, 3, t3 # get byte within longword
+
+20:
+ ldl v0, (t0) # get the longword
+ subl a2, 1, a2 # decrement count
+ extbl v0, t3, v0 # get the correct byte
+ stb v0, (a1) # cheat and let the assembler do it
+ addl a1, 1, a1 # next byte in buffer
+ bne a2, 20b # loop if more bytes to move
+30:
+ ret zero, (ra)
+
+#if DBG
+40:
+ //
+ // HAE is non-zero or not a bus address, this should never happen!
+ //
+ BREAK_DEBUG_STOP
+ or a0, zero, a2 # save bad address in a2
+ ldil a0, BAD_QVA
+ jsr t12, KeBugCheck # crash if illegal access
+#endif
+
+
+ .end READ_PORT_BUFFER_UCHAR
+
+ LEAF_ENTRY(READ_PORT_BUFFER_USHORT)
+
+/*++
+
+Routine Description:
+
+ Reads from the specified port buffer address. Since there are no
+ PORT buffers on Jensen, there is no code to handle COMBO space in
+ this routine. Note: a0, a1 should be word aligned.
+
+
+Arguments:
+
+ a0 QVA of source port.
+ a1 VA of destination buffer in memory.
+ a2 Number of words to move (Count).
+
+
+Return Value:
+
+ None
+
+--*/
+
+
+#if DBG
+ srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
+ and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
+ xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
+ bne t1, 40f # br if not a bus address - error
+ and t2, 3, t4 # get HAE index
+
+ //
+ // Check if HAE is non-zero. For IO space access this should never
+ // be non-zero!
+ //
+ bne t4, 40f # br if HAE non-zero - error
+#endif
+
+ beq a2, 30f # leave now if nothing to move
+ ldah t0, QVA_CONTROL(zero) # get mask clear bits
+ bic a0, t0, t0 # clear QVA control bits a0<63:25>
+
+ //
+ // Note - at this point we know bits t0<63:25> = 0
+ //
+ // We will now ignore the IO/MEM bit and generate bits PA<63:32>
+ // knowing that we are in EISA IO space. This will save 2 instructions
+ // and require that the PORT routines only be used for access to IO
+ // space.
+ //
+ ldiq t4, EISA_IO # form upper bits of PA
+ sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
+ sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
+ or t0, t4, t0 # generate superpage address
+ and a0, 3, t3 # get word within longword
+
+20:
+ ldl v0, EISA_WORD_LEN(t0) # get the word within the longword
+ subl a2, 1, a2 # decrement count
+ extwl v0, t3, v0 # get the correct word
+ stw v0, (a1) # cheat and let the assembler do it
+ addl a1, 2, a1 # next word in buffer
+ bne a2, 20b # loop if more bytes to move
+30:
+ ret zero, (ra)
+
+#if DBG
+40:
+ //
+ // HAE is non-zero or not a bus address, this should never happen!
+ //
+ BREAK_DEBUG_STOP
+ or a0, zero, a2 # save bad address in a2
+ ldil a0, BAD_QVA
+ jsr t12, KeBugCheck # crash if illegal access
+#endif
+
+
+ .end READ_PORT_BUFFER_USHORT
+
+ LEAF_ENTRY(READ_PORT_BUFFER_ULONG)
+
+/*++
+
+Routine Description:
+
+ Reads from the specified port buffer address. Since there are no
+ PORT buffers on Jensen, there is no code to handle COMBO space in
+ this routine. Note: a0, a1 should be longword aligned.
+
+
+Arguments:
+
+ a0 QVA of source port.
+ a1 VA of destination buffer in memory.
+ a2 Number of longs to move (Count).
+
+Return Value:
+
+ None
+
+
+--*/
+
+
+#if DBG
+ srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
+ and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
+ xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
+ bne t1, 40f # br if not a bus address - error
+ and t2, 3, t4 # get HAE index
+
+ //
+ // Check if HAE is non-zero. For IO space access this should never
+ // be non-zero!
+ //
+ bne t4, 40f # br if HAE non-zero - error
+#endif
+
+ beq a2, 30f # leave now if nothing to move
+ ldah t0, QVA_CONTROL(zero) # get mask clear bits
+ bic a0, t0, t0 # clear QVA control bits a0<63:25>
+
+ //
+ // Note - at this point we know bits t0<63:25> = 0
+ //
+ // We will now ignore the IO/MEM bit and generate bits PA<63:32>
+ // knowing that we are in EISA IO space. This will save 2 instructions
+ // and require that the PORT routines only be used for access to IO
+ // space.
+ //
+ ldiq t4, EISA_IO # form upper bits of PA
+ sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
+ sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
+ or t0, t4, t0 # generate superpage address
+
+20:
+ ldl v0, EISA_LONG_LEN(t0) # get the longword
+ subl a2, 1, a2 # decrement count
+ stl v0, (a1) # save the longword
+ addl a1, 4, a1 # next byte in buffer
+ bne a2, 20b # loop if more bytes to move
+30:
+ ret zero, (ra)
+
+#if DBG
+40:
+ //
+ // HAE is non-zero or not a bus address, this should never happen!
+ //
+ BREAK_DEBUG_STOP
+ or a0, zero, a2 # save bad address in a2
+ ldil a0, BAD_QVA
+ jsr t12, KeBugCheck # crash if illegal access
+#endif
+
+
+ .end READ_PORT_BUFFER_ULONG
+
+
+ LEAF_ENTRY(WRITE_PORT_BUFFER_UCHAR)
+
+/*++
+
+Routine Description:
+
+ Writes to the specified port buffer address. Since there are no
+ PORT buffers on Jensen, there is no code to handle COMBO space in
+ this routine.
+
+
+Arguments:
+
+ a0 QVA of destination port.
+ a1 VA of source buffer in memory.
+ a2 Number of bytes to move (Count).
+
+
+Return Value:
+
+ None
+
+--*/
+
+#if DBG
+ srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
+ and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
+ xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
+ bne t1, 40f # br if not a bus address - error
+ and t2, 3, t4 # get HAE index
+
+ //
+ // Check if HAE is non-zero. For IO space access this should never
+ // be non-zero!
+ //
+ bne t4, 40f # br if HAE non-zero - error
+#endif
+
+ beq a2, 30f # leave now if nothing to move
+ ldah t0, QVA_CONTROL(zero) # get mask clear bits
+ bic a0, t0, t0 # clear QVA control bits a0<63:25>
+
+ //
+ // Note - at this point we know bits t0<63:25> = 0
+ //
+ // We will now ignore the IO/MEM bit and generate bits PA<63:32>
+ // knowing that we are in EISA IO space. This will save 2 instructions
+ // and require that the PORT routines only be used for access to IO
+ // space.
+ //
+ ldiq t4, EISA_IO # form upper bits of PA
+ sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
+ sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
+ or t0, t4, t0 # generate superpage address
+ and a0, 3, t3 # get byte within longword
+
+20:
+ ldq_u t1, 0(a1) # get quad surrounding byte
+ subl a2, 1, a2 # decrement count
+ extbl t1, a1, t1 # extract appropriate byte
+ addl a1, 1, a1 # increment buffer pointer
+ insbl t1, t3, t1 # put byte to appropriate lane
+ stl t1, 0(t0) # store to port
+ mb # push writes off chip
+ bne a2, 20b # loop if more bytes to move
+30:
+ ret zero, (ra)
+
+#if DBG
+40:
+ //
+ // HAE is non-zero or not a bus address, this should never happen!
+ //
+ BREAK_DEBUG_STOP
+ or a0, zero, a2 # save bad address in a2
+ ldil a0, BAD_QVA
+ jsr t12, KeBugCheck # crash if illegal access
+#endif
+
+
+ .end WRITE_PORT_BUFFER_UCHAR
+
+ LEAF_ENTRY(WRITE_PORT_BUFFER_USHORT)
+
+/*++
+
+Routine Description:
+
+ Writes to the specified port buffer address. Since there are no
+ PORT buffers on Jensen, there is no code to handle COMBO space in
+ this routine. Note: a0, a1 should be word aligned.
+
+
+Arguments:
+
+ a0 QVA of destination port.
+ a1 VA of source buffer in memory.
+ a2 Number of words to move (Count).
+
+
+Return Value:
+
+ None
+
+--*/
+
+
+#if DBG
+ srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
+ and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
+ xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
+ bne t1, 40f # br if not a bus address - error
+ and t2, 3, t4 # get HAE index
+
+ //
+ // Check if HAE is non-zero. For IO space access this should never
+ // be non-zero!
+ //
+ bne t4, 40f # br if HAE non-zero - error
+#endif
+
+ beq a2, 30f # leave now if nothing to move
+ ldah t0, QVA_CONTROL(zero) # get mask clear bits
+ bic a0, t0, t0 # clear QVA control bits a0<63:25>
+
+ //
+ // Note - at this point we know bits t0<63:25> = 0
+ //
+ // We will now ignore the IO/MEM bit and generate bits PA<63:32>
+ // knowing that we are in EISA IO space. This will save 2 instructions
+ // and require that the PORT routines only be used for access to IO
+ // space.
+ //
+ ldiq t4, EISA_IO # form upper bits of PA
+ sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
+ sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
+ or t0, t4, t0 # generate superpage address
+ and a0, 3, t3 # get byte within longword
+
+20:
+ ldq_u t1, (a1) # get quad surrounding word
+ subl a2, 1, a2 # decrement count
+ extwl t1, a1, t1 # extract appropriate word
+ addl a1, 2, a1 # increment buffer pointer
+ inswl t1, t3, t1 # put word to appropriate lane
+ stl t1, EISA_WORD_LEN(t0) # store the word to the port
+ mb # push writes off chip
+ bne a2, 20b # loop if more bytes to move
+30:
+ ret zero, (ra)
+
+#if DBG
+40:
+ //
+ // HAE is non-zero or not a bus address, this should never happen!
+ //
+ BREAK_DEBUG_STOP
+ or a0, zero, a2 # save bad address in a2
+ ldil a0, BAD_QVA
+ jsr t12, KeBugCheck # crash if illegal access
+#endif
+
+
+ .end WRITE_PORT_BUFFER_USHORT
+
+ LEAF_ENTRY(WRITE_PORT_BUFFER_ULONG)
+
+/*++
+
+Routine Description:
+
+ Writes to the specified port buffer address. Since there are no
+ PORT buffers on Jensen, there is no code to handle COMBO space in
+ this routine. Note: a0, a1 should be longword aligned.
+
+
+Arguments:
+
+ a0 QVA of destination port.
+ a1 VA of source buffer in memory.
+ a2 Number of longs to move (Count).
+
+Return Value:
+
+ None
+
+
+--*/
+
+
+#if DBG
+ srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
+ and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
+ xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
+ bne t1, 40f # br if not a bus address - error
+ and t2, 3, t4 # get HAE index
+
+ //
+ // Check if HAE is non-zero. For IO space access this should never
+ // be non-zero!
+ //
+ bne t4, 40f # br if HAE non-zero - error
+#endif
+
+ beq a2, 30f # leave now if nothing to move
+ ldah t0, QVA_CONTROL(zero) # get mask clear bits
+ bic a0, t0, t0 # clear QVA control bits a0<63:25>
+
+ //
+ // Note - at this point we know bits t0<63:25> = 0
+ //
+ // We will now ignore the IO/MEM bit and generate bits PA<63:32>
+ // knowing that we are in EISA IO space. This will save 2 instructions
+ // and require that the PORT routines only be used for access to IO
+ // space.
+ //
+ ldiq t4, EISA_IO # form upper bits of PA
+ sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
+ sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
+ or t0, t4, t0 # generate superpage address
+
+20:
+ ldl t1, (a1) # a1 must be longword aligned
+ subl a2, 1, a2 # decrement count
+ stl t1, EISA_LONG_LEN(t0) # store longword to port
+ mb # push writes off chip
+ addl a1, 4, a1 # increment buffer pointer
+ bne a2, 20b # loop if more bytes to move
+30:
+ ret zero, (ra)
+
+#if DBG
+40:
+ //
+ // HAE is non-zero or not a bus address, this should never happen!
+ //
+ BREAK_DEBUG_STOP
+ or a0, zero, a2 # save bad address in a2
+ ldil a0, BAD_QVA
+ jsr t12, KeBugCheck # crash if illegal access
+#endif
+
+
+ .end WRITE_PORT_BUFFER_ULONG
+
+
+ LEAF_ENTRY(READ_REGISTER_BUFFER_UCHAR)
+/*++
+
+Routine Description:
+
+ Reads from the specified buffer address. This routine only works
+ with EISA memory space, since there are no REGISTER buffers in
+ COMBO space on Jensen.
+
+
+Arguments:
+
+ a0 QVA of source buffer.
+ a1 VA of destination buffer in memory.
+ a2 Number of bytes to move (Count).
+
+
+Return Value:
+
+ None
+
+--*/
+
+ srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
+ and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
+ xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
+ and a0, 3, t3 # get byte within longword
+ bne t1, 120f # br if not a bus address
+
+ ldah t0, QVA_CONTROL(zero) # get mask clear bits
+ and t2, 3, t4 # get HAE index
+ bic a0, t0, t0 # clear QVA control bits a0<63:25>
+
+ ldiq t2, EISA_MEMORY # form upper bits of PA
+ sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
+ sll t2, IO_HI_SHIFT, t2 # shift upper bits into position
+ or t0, t2, t0 # generate superpage address
+
+ //
+ // Note - at this point we know bits t0<63:25> = 0
+ //
+ // Check if we have to load the HAE with a non-zero value. This
+ // is considered non-standard, but it is supported. Loading the HAE
+ // requires additional synchronization.
+ //
+ bne t4, 130f # br if HAE has to be set up
+
+ //
+ // get source buffer aligned
+ //
+ // t0 = superpage bus address of source
+ // a1 = destination va
+ // a2 = byte count
+ // t3 = byte offset (in a LONGWORD)
+ //
+
+ ldiq t10, EISA_BITS_ONEZERO # mask for EISA address 1..0
+ and t0, t10, t9 # t9 holds EISA address bits 1..0
+ srl t9, EISA_BIT_SHIFT, t9 # position bits down low
+ and a1, 3, t8 # 1..0 of destination VA
+ xor t9, t8, t8 # compare alignment of src and dst
+ bne t8, 70f # use unaligned code if not aligned
+
+ // transfer can be done using longword fetch/store since the
+ // source and destination are sympathetically aligned
+
+ beq t9, 20f # branch if src is already longaligned
+
+ // Move bytes until source is at a longword boundary
+
+10: beq a2, 60f # while count > 0
+
+ ldl v0, 0(t0) # get the longword
+ subl a2, 1, a2 # decrement count
+ extbl v0, t3, v0 # get the correct byte
+ stb v0, (a1) # cheat and let the assembler do it
+ addl a1, 1, a1 # next byte in buffer
+ addq t0, EISA_BYTE_OFFSET, t0 # next I/O address
+ addl t3, 1, t3 # next byte in lane
+ and t3, 3, t3 # longword lanes
+ bne t3, 10b # while unaligned loop here
+
+ // move aligned longwords
+
+20: srl a2, 2, t3 # longwords to move
+ beq t3, 40f # done moving longwords?
+
+ lda t11, EISA_LONG_OFFSET(zero) # longword stride in EISA space
+30: ldl t4, EISA_LONG_LEN(t0) # fetch longword from EISA
+ addl a1, 4, a1 # increment dst VA
+ subl t3, 1, t3 # decr longwords to move
+ stl t4, -4(a1) # store to dst
+ addq t0, t11, t0 # increment src pointer
+ bne t3, 30b # while longwords remain
+
+40: and a2, 3, a2 # bytes remaining
+ //bis zero, zero, t3 # byte lane 0
+
+
+ // non-aligned and driblets move
+
+50: beq a2, 60f # while count > 0
+
+ ldl v0, 0(t0) # get the longword
+ subl a2, 1, a2 # decrement count
+ extbl v0, t3, v0 # get the correct byte
+ stb v0, (a1) # cheat and let the assembler do it
+ addl a1, 1, a1 # next byte in buffer
+ addq t0, EISA_BYTE_OFFSET, t0 # next I/O address
+ addl t3, 1, t3 # next byte in lane
+ and t3, 3, t3 # longword lanes
+ br zero, 50b # end while
+60:
+
+ ret zero, (ra)
+//
+// source EISA alignment != destination memory alignment
+// move enough bytes to longword align the EISA source
+// then move 32bit (longwords) storing unaligned into memory
+// then move residual bytes
+//
+// t0 = superpage address of source
+// a1 = virtual address of destination
+// a2 = bytes to move
+// t9 = low 2 bits of EISA superpage address
+// t3 = low 2 bits of EISA QVA
+//
+
+70:
+ beq t9, 90f # branch if src is longaligned
+
+// Move bytes until EISA src is at a longword boundary or bytes exhausted
+
+80: beq a2, 60b # while count > 0
+
+ ldl v0, 0(t0) # get the longword
+ subl a2, 1, a2 # decrement count
+ extbl v0, t3, v0 # get the correct byte
+ stb v0, (a1) # cheat and let the assembler do it
+ addl a1, 1, a1 # next byte in buffer
+ addq t0, EISA_BYTE_OFFSET, t0 # next I/O address
+ addl t3, 1, t3 # next byte in lane
+ and t3, 3, t3 # longword lanes
+ bne t3, 80b # while not aligned
+
+// align EISA source, unaligned memory destination
+
+90:
+ srl a2, 3, t3 # t3 = quadwords to move
+ beq t3, 110f # finish if no longwords
+
+100:
+ ldl t1, EISA_LONG_LEN(t0) # load longword 0 from EISA
+ ldq_u t4, 0(a1) # load destination quad for merge
+ ldq_u t5, 7(a1) #
+ subl t3, 1, t3 # decrement quadwords to move
+ ldl t2, EISA_SECOND_LONG(t0) # load longword 1 from EISA
+ mskql t4, a1, t4 # mask of merge bytes
+ mskqh t5, a1, t5 # mask of merge bytes
+ zap t1, 0xf0, t1 # clear high longword for long 0
+ sll t2, 32, t2 # get long 1 to high longword
+ bis t1, t2, t1 # merge read quadword together
+ lda t0, EISA_QUAD_OFFSET(t0) # increment to next quadword
+ insql t1, a1, t6 # position low quadword for merge
+ insqh t1, a1, t7 # position high quadword for merge
+ bis t4, t6, t4 # merge new data, low quadword
+ bis t5, t7, t5 # merge new data, high quadword
+ stq_u t5, 7(a1) # write high quadword
+ stq_u t4, 0(a1) # write low quadword
+ lda a1, 8(a1) # increment memory pointer
+ bne t3, 100b # while quadwords to move
+
+110:
+ and a2, 7, a2 # bytes remaining to move
+ //bis zero, zero, t3 # byte line position of next byte
+ br zero, 50b # go back to byte mover
+
+120:
+
+//
+// This must be non I/O space access
+//
+ bis a0, zero, t0 # save source address
+ bis a1, zero, a0 # move destination address to a0
+ bis t0, zero, a1 # move source address to a1
+ br zero, RtlMoveMemory # Let Rtl routine handle move
+
+
+
+130:
+
+//
+// setup HAE
+//
+// a0 = QVA
+// a1 = destination va
+// a2 = byte count
+// t0 = superpage bus address of source
+// t3 = byte offset (in a LONGWORD)
+// t4 = HAE index
+// t2 = upper bits of EISA superpage address
+//
+ lda t1, HalpHaeTable # get address of HAE table
+ ldiq t2, COMBO_IO # form upper bits of HAE
+ addl t4, t1, t1 # get address of new HAE value
+ sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
+ ldq_u t4, (t1) # get new HAE value
+ extbl t4, t1, t4 # ...
+
+#if DBG
+ // Note: the value in t4 should never be zero!
+ beq t4, 250f # br if new HAE value is zero!
+#endif
+
+ ldiq t1, HAE_PHYSICAL_BASEL # get base address of HAE register
+ or t1, t2, t1 # generate HAE superpage address
+
+ bis a1, zero, t6 # save a1, since SWAP_IRQL destroys it
+ bis a2, zero, t7 # save a2, since SWAP_IRQL destroys it
+ //
+ // Raise IRQL to device level to block other accesses to EISA memory
+ //
+ ldiq a0, DEVICE_LEVEL # get device level IRQL
+ SWAP_IRQL # raise IRQL to DEVICE_LEVEL
+ bis v0, zero, a0 # save original IRQL
+
+ bis t6, zero, a1 # restore a1
+ bis t7, zero, a2 # restore a2
+
+ //
+ // We will not bother to save the original HAE value. The value
+ // in the HAE must be zero... otherwise synchronization is broken.
+ // In debug mode, we will check the HAE however.
+ //
+#if DBG
+ ldl t8, (t1) # get original HAE value
+ bne t8, 250f # br if HAE is non-zero - error!
+#endif
+
+ stl t4, (t1) # write new HAE value
+ mb # force it out
+
+ //
+ // Now we can read the bytes from the EISA bus
+ //
+ // t8 = original HAE value (debug only)
+ // a0 = original IRQL
+ //
+ // t0 = superpage bus address of source
+ // t1 = address of HAE register
+ // a1 = destination va
+ // a2 = byte count
+ // t3 = byte offset (in a LONGWORD)
+ //
+
+ ldiq t10, EISA_BITS_ONEZERO # mask for EISA address 1..0
+ and t0, t10, t9 # t9 holds EISA address bits 1..0
+ srl t9, EISA_BIT_SHIFT, t9 # position bits down low
+ and a1, 3, t10 # 1..0 of destination VA
+ xor t9, t10, t10 # compare alignment of src and dst
+ bne t10, 200f # use unaligned code if not aligned
+
+ // transfer can be done using longword fetch/store since the
+ // source and destination are sympathetically aligned
+
+ beq t9, 150f # branch if src is already longaligned
+
+ // Move bytes until source is at a longword boundary
+
+140: beq a2, 190f # while count > 0
+
+ ldl v0, 0(t0) # get the longword
+ subl a2, 1, a2 # decrement count
+ extbl v0, t3, v0 # get the correct byte
+ stb v0, (a1) # cheat and let the assembler do it
+ addl a1, 1, a1 # next byte in buffer
+ addq t0, EISA_BYTE_OFFSET, t0 # next I/O address
+ addl t3, 1, t3 # next byte in lane
+ and t3, 3, t3 # longword lanes
+ bne t3, 140b # while unaligned loop here
+
+ // move aligned longwords
+
+150: srl a2, 2, t3 # longwords to move
+ beq t3, 170f # done moving longwords?
+
+ lda t11, EISA_LONG_OFFSET(zero) # longword stride in EISA space
+160: ldl t4, EISA_LONG_LEN(t0) # fetch longword from EISA
+ addl a1, 4, a1 # increment dst VA
+ subl t3, 1, t3 # decr longwords to move
+ stl t4, -4(a1) # store to dst
+ addq t0, t11, t0 # increment src pointer
+ bne t3, 160b # while longwords remain
+
+170: and a2, 3, a2 # bytes remaining
+ //bis zero, zero, t3 # byte lane 0
+
+
+ // non-aligned and driblets move
+
+180: beq a2, 190f # while count > 0
+
+ ldl v0, 0(t0) # get the longword
+ subl a2, 1, a2 # decrement count
+ extbl v0, t3, v0 # get the correct byte
+ stb v0, (a1) # cheat and let the assembler do it
+ addl a1, 1, a1 # next byte in buffer
+ addq t0, EISA_BYTE_OFFSET, t0 # next I/O address
+ addl t3, 1, t3 # next byte in lane
+ and t3, 3, t3 # longword lanes
+ br zero, 180b # end while
+190:
+ //
+ // Restore HAE before exiting
+ //
+ stl zero, (t1) # restore original HAE value
+ mb # force it out
+
+ //
+ // Lower IRQL, original IRQL in a0
+ //
+ SWAP_IRQL # restore original IRQL
+
+ ret zero, (ra)
+//
+// source EISA alignment != destination memory alignment
+// move enough bytes to longword align the EISA source
+// then move 32bit (longwords) storing unaligned into memory
+// then move residual bytes
+//
+// t8 = original HAE value (debug only)
+// a0 = original IRQL
+//
+// t0 = superpage address of source
+// a1 = virtual address of destination
+// a2 = bytes to move
+// t9 = low 2 bits of EISA superpage address
+// t3 = low 2 bits of EISA QVA
+//
+
+200:
+ beq t9, 220f # branch if src is longaligned
+
+// Move bytes until EISA src is at a longword boundary or bytes exhausted
+
+210: beq a2, 190b # while count > 0
+
+ ldl v0, 0(t0) # get the longword
+ subl a2, 1, a2 # decrement count
+ extbl v0, t3, v0 # get the correct byte
+ stb v0, (a1) # cheat and let the assembler do it
+ addl a1, 1, a1 # next byte in buffer
+ addq t0, EISA_BYTE_OFFSET, t0 # next I/O address
+ addl t3, 1, t3 # next byte in lane
+ and t3, 3, t3 # longword lanes
+ bne t3, 210b # while not aligned
+
+// align EISA source, unaligned memory destination
+
+220:
+ srl a2, 3, t3 # t3 = quadwords to move
+ beq t3, 240f # finish if no longwords
+
+230:
+ ldl v0, EISA_LONG_LEN(t0) # load longword 0 from EISA
+ ldq_u t4, 0(a1) # load destination quad for merge
+ ldq_u t5, 7(a1) #
+ subl t3, 1, t3 # decrement quadwords to move
+ ldl t2, EISA_SECOND_LONG(t0) # load longword 1 from EISA
+ mskql t4, a1, t4 # mask of merge bytes
+ mskqh t5, a1, t5 # mask of merge bytes
+ zap v0, 0xf0, v0 # clear high longword for long 0
+ sll t2, 32, t2 # get long 1 to high longword
+ bis v0, t2, v0 # merge read quadword together
+ lda t0, EISA_QUAD_OFFSET(t0) # increment to next quadword
+ insql v0, a1, t6 # position low quadword for merge
+ insqh v0, a1, t7 # position high quadword for merge
+ bis t4, t6, t4 # merge new data, low quadword
+ bis t5, t7, t5 # merge new data, high quadword
+ stq_u t5, 7(a1) # write high quadword
+ stq_u t4, 0(a1) # write low quadword
+ lda a1, 8(a1) # increment memory pointer
+ bne t3, 230b # while quadwords to move
+
+240:
+ and a2, 7, a2 # bytes remaining to move
+ //bis zero, zero, t3 # byte line position of next byte
+ br zero, 180b # go back to byte mover
+
+#if DBG
+250:
+ // New HAE value is zero!
+ BREAK_DEBUG_STOP
+ ldil a0, BAD_QVA
+ jsr t12, KeBugCheck # crash if bad HAE index
+#endif
+
+
+ .end READ_REGISTER_BUFFER_UCHAR
+
+
+ LEAF_ENTRY(READ_REGISTER_BUFFER_USHORT)
+
+/*++
+
+Routine Description:
+
+ Reads from the specified buffer address. This routine only works
+ with EISA memory space, since there are no REGISTER buffers in
+ COMBO space on Jensen.
+
+ Both the input buffer and output buffer should be word aligned.
+
+Arguments:
+
+ a0 QVA of source buffer.
+ a1 VA of destination buffer in memory.
+ a2 Number of words to move (Count).
+
+
+Return Value:
+
+ None
+
+--*/
+
+ beq a2, 30f # leave is nothing to do
+ srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
+ and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
+ xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
+ and a0, 3, t3 # get byte within longword
+ bne t1, 40f # br if not a bus address
+
+ ldah t0, QVA_CONTROL(zero) # get mask clear bits
+ and t2, 3, t4 # get HAE index alone
+ bic a0, t0, t0 # clear QVA control bits a0<63:25>
+
+ ldiq t2, EISA_MEMORY # form upper bits of PA
+ sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
+ sll t2, IO_HI_SHIFT, t2 # shift upper bits into position
+ or t0, t2, t0 # generate superpage address
+ or t0, EISA_WORD_LEN, t0 # or in the WORD byte enables
+
+ //
+ // Note - at this point we know bits t0<63:25> = 0
+ //
+ // Check if we have to load the HAE with a non-zero value. This
+ // is considered non-standard, but it is supported. Loading the HAE
+ // requires additional synchronization.
+ //
+ bne t4, 100f # br if HAE has to be set up
+
+20:
+ ldl v0, 0(t0) # get the longword
+ subl a2, 1, a2 # decrement count
+ extwl v0, t3, v0 # get the correct
+ stw v0, (a1) # cheat and let the assembler do it
+ addl a1, 2, a1 # next word in buffer
+ addq t0, EISA_SHORT_OFFSET, t0 # next I/O address
+ addl t3, 2, t3 # next word in lane
+ and t3, 3, t3 # longword lanes
+ bne a2, 20b # end while
+30:
+ ret zero, (ra)
+
+40:
+ //
+ // This must be non I/O space access
+ //
+ bis a0, zero, t0 # save source address
+ sll a2, 1, a2 # convert word count to byte count
+ bis a1, zero, a0 # move destination address to a0
+ bis t0, zero, a1 # move source address to a1
+ br zero, RtlMoveMemory # Let Rtl routine handle move
+
+100:
+
+//
+// setup HAE
+//
+// a0 = QVA of source
+// a1 = destination va
+// a2 = word count
+// t0 = superpage bus address of source
+// t3 = byte offset for source (within a LONGWORD)
+// t4 = HAE index
+// t2 = upper bits of EISA superpage address
+//
+
+ lda t1, HalpHaeTable # get address of HAE table
+ ldiq t2, COMBO_IO # form upper bits of HAE
+ addl t4, t1, t1 # get address of new HAE value
+ sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
+ ldq_u t4, (t1) # get new HAE value
+ extbl t4, t1, t4 # ...
+
+#if DBG
+ // Note: the value in t4 should never be zero!
+ beq t4, 150f # br if new HAE value is zero!
+#endif
+
+ ldiq t1, HAE_PHYSICAL_BASEL # get base address of HAE register
+ or t1, t2, t1 # generate HAE superpage address
+
+ bis a1, zero, t6 # save a1, since SWAP_IRQL destroys it
+ bis a2, zero, t7 # save a2, since SWAP_IRQL destroys it
+ //
+ // Raise IRQL to device level to block other accesses to EISA memory
+ //
+ ldiq a0, DEVICE_LEVEL # get device level IRQL
+ SWAP_IRQL # raise IRQL to DEVICE_LEVEL
+ bis v0, zero, a0 # save original IRQL
+
+ //
+ // We will not bother to save the original HAE value. The value
+ // in the HAE must be zero... otherwise synchronization is broken.
+ // In debug mode, we will check the HAE however.
+ //
+#if DBG
+ ldl t8, (t1) # get original HAE value
+ bne t8, 150f # br if HAE is non-zero - error!
+#endif
+
+ stl t4, (t1) # write new HAE value
+ mb # force it out
+
+ //
+ // Now we can read the words from the EISA bus
+ //
+ // t8 = original HAE value (debug only)
+ // a0 = original IRQL
+ //
+ // t0 = superpage bus address of source
+ // t1 = address of HAE register
+ // t6 = destination va
+ // t7 = word count
+ // t3 = byte offset for source (within a LONGWORD)
+ //
+
+120:
+ ldl v0, 0(t0) # get the longword
+ subl t7, 1, t7 # decrement count
+ extwl v0, t3, v0 # get the correct
+ stw v0, (t6) # cheat and let the assembler do it
+ addl t6, 2, t6 # next word in buffer
+ addq t0, EISA_SHORT_OFFSET, t0 # next I/O address
+ addl t3, 2, t3 # next word in lane
+ and t3, 3, t3 # longword lanes
+ bne t7, 120b # end while
+130:
+ //
+ // Restore HAE before exiting
+ //
+ stl zero, (t1) # restore original HAE value
+ mb # force it out
+
+ //
+ // Lower IRQL, original IRQL in a0
+ //
+ SWAP_IRQL # restore original IRQL
+
+ ret zero, (ra)
+
+#if DBG
+150:
+ // New HAE value is zero!
+ BREAK_DEBUG_STOP
+ ldil a0, BAD_QVA
+ jsr t12, KeBugCheck # crash if bad HAE index
+#endif
+
+
+ .end READ_REGISTER_BUFFER_USHORT
+
+
+ LEAF_ENTRY(READ_REGISTER_BUFFER_ULONG)
+
+/*++
+
+Routine Description:
+
+ Reads from the specified buffer address. This routine only works
+ with EISA memory space, since there are no REGISTER buffers in
+ COMBO space on Jensen.
+
+ Both the input buffer and output buffer should be longword aligned.
+
+Arguments:
+
+ a0 QVA of source buffer.
+ a1 VA of destination buffer in memory.
+ a2 Number of longs to move (Count).
+
+
+Return Value:
+
+ None
+
+--*/
+
+ beq a2, 30f # leave if nothing to do
+ srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
+ and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
+ xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
+ bne t1, 40f # br if not a bus address
+
+ ldah t0, QVA_CONTROL(zero) # get mask clear bits
+ and t2, 3, t4 # get HAE index
+ bic a0, t0, t0 # clear QVA control bits a0<63:25>
+
+ ldiq t2, EISA_MEMORY # form upper bits of PA
+ sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
+ sll t2, IO_HI_SHIFT, t2 # shift upper bits into position
+ or t0, t2, t0 # generate superpage address
+ or t0, EISA_LONG_LEN, t0 # or in the LONGWORD byte enables
+
+ //
+ // Note - at this point we know bits t0<63:25> = 0
+ //
+ // Check if we have to load the HAE with a non-zero value. This
+ // is considered non-standard, but it is supported. Loading the HAE
+ // requires additional synchronization.
+ //
+ bne t4, 100f # br if HAE has to be set up
+
+20:
+ ldl v0, 0(t0) # get the longword
+ subl a2, 1, a2 # decrement count
+ stl v0,(a1) # cheat and let the assembler do it
+ addl a1, 4, a1 # next longword in buffer
+ addq t0, EISA_LONG_OFFSET, t0 # next I/O address
+ bne a2, 20b # end while
+30:
+ ret zero, (ra)
+
+40:
+ //
+ // This must be non I/O space access
+ //
+
+ bis a0, zero, t0 # save source address
+ s4addl a2, zero, a2 # convert longword count to byte count
+ bis a1, zero, a0 # move destination address to a0
+ bis t0, zero, a1 # move source address to a1
+ br zero, RtlMoveMemory # Let Rtl routine handle move
+
+100:
+
+//
+// setup HAE
+//
+// a0 = QVA of source
+// a1 = destination va
+// a2 = longword count
+// t0 = superpage bus address of source
+// t4 = HAE index
+// t2 = upper bits of EISA superpage address
+//
+
+ lda t1, HalpHaeTable # get address of HAE table
+ ldiq t2, COMBO_IO # form upper bits of HAE
+ addl t4, t1, t1 # get address of new HAE value
+ sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
+ ldq_u t4, (t1) # get new HAE value
+ extbl t4, t1, t4 # ...
+
+#if DBG
+ // Note: the value in t4 should never be zero!
+ beq t4, 150f # br if new HAE value is zero!
+#endif
+
+ ldiq t1, HAE_PHYSICAL_BASEL # get base address of HAE register
+ or t1, t2, t1 # generate HAE superpage address
+
+ bis a1, zero, t6 # save a1, since SWAP_IRQL destroys it
+ bis a2, zero, t7 # save a2, since SWAP_IRQL destroys it
+ //
+ // Raise IRQL to device level to block other accesses to EISA memory
+ //
+ ldiq a0, DEVICE_LEVEL # get device level IRQL
+ SWAP_IRQL # raise IRQL to DEVICE_LEVEL
+ bis v0, zero, a0 # save original IRQL
+
+ //
+ // We will not bother to save the original HAE value. The value
+ // in the HAE must be zero... otherwise synchronization is broken.
+ // In debug mode, we will check the HAE however.
+ //
+#if DBG
+ ldl t8, (t1) # get original HAE value
+ bne t8, 150f # br if HAE is non-zero - error!
+#endif
+
+ stl t4, (t1) # write new HAE value
+ mb # force it out
+
+ //
+ // Now we can read the words from the EISA bus
+ //
+ // t8 = original HAE value (debug only)
+ // a0 = original IRQL
+ //
+ // t0 = superpage bus address of source
+ // t1 = address of HAE register
+ // t6 = destination va
+ // t7 = longword count
+ //
+
+120:
+ ldl v0, 0(t0) # get the longword
+ subl t7, 1, t7 # decrement count
+ stl v0, (t6) # cheat and let the assembler do it
+ addl t6, 4, t6 # next word in buffer
+ addq t0, EISA_LONG_OFFSET, t0 # next I/O address
+ bne t7, 120b # end while
+130:
+ //
+ // Restore HAE before exiting
+ //
+ stl zero, (t1) # restore original HAE value
+ mb # force it out
+
+ //
+ // Lower IRQL, original IRQL in a0
+ //
+ SWAP_IRQL # restore original IRQL
+
+ ret zero, (ra)
+
+#if DBG
+150:
+ // New HAE value is zero!
+ BREAK_DEBUG_STOP
+ ldil a0, BAD_QVA
+ jsr t12, KeBugCheck # crash if bad HAE index
+#endif
+
+
+ .end READ_REGISTER_BUFFER_ULONG
+
+ LEAF_ENTRY(WRITE_REGISTER_BUFFER_UCHAR)
+
+/*++
+
+Routine Description:
+
+ Writes to the specified buffer address. This routine only works
+ with EISA memory space, since there are no REGISTER buffers in
+ COMBO space on Jensen.
+
+
+Arguments:
+
+ a0 QVA of destination buffer in I/O space.
+ a1 VA of source buffer in memory.
+ a2 Number of bytes to move (Count).
+
+
+Return Value:
+
+ None
+
+--*/
+
+ srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
+ and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
+ xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
+ and a0, 3, t3 # get byte within longword
+ bne t1, 120f # br if not a bus address
+
+ ldah t0, QVA_CONTROL(zero) # get mask clear bits
+ and t2, 3, t4 # get HAE index
+ bic a0, t0, t0 # clear QVA control bits a0<63:25>
+
+ ldiq t2, EISA_MEMORY # form upper bits of PA
+ sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
+ sll t2, IO_HI_SHIFT, t2 # shift upper bits into position
+ or t0, t2, t0 # generate superpage address
+
+ //
+ // Note - at this point we know bits t0<63:25> = 0
+ //
+ // Check if we have to load the HAE with a non-zero value. This
+ // is considered non-standard, but it is supported. Loading the HAE
+ // requires additional synchronization.
+ //
+ bne t4, 130f # br if HAE has to be set up
+
+ //
+ //
+ // get destination buffer aligned
+ //
+ // t0 = superpage destination bus address
+ // a1 = source va
+ // a2 = byte count
+ // t3 = byte offset (in a LONGWORD)
+ //
+
+ ldiq t10, EISA_BITS_ONEZERO # mask for EISA address 1..0
+ and t0, t10, t9 # t9 holds EISA address bits 1..0
+ srl t9, EISA_BIT_SHIFT, t9 # position bits
+ and a1, 3, t8 # 1..0 of destination VA
+ xor t9, t8, t8 # compare alignment of src and dst
+ bne t8, 70f # use unaligned move if not aligned
+
+ // transfer can be done using longword fetch/store since the
+ // source and destination are sympathetically aligned
+
+ beq t9, 20f # br if dest is already longaligned
+
+// Move bytes until destination is at a longword boundary or bytes exhausted
+
+10: beq a2, 60f # while count > 0
+
+ ldq_u t1, 0(a1) # get quad surrounding byte
+ subl a2, 1, a2 # decrement count
+ extbl t1, a1, t1 # extract appropriate byte
+ addl a1, 1, a1 # increment buffer pointer
+ insbl t1, t3, t1 # get proper lane
+ stl t1, 0(t0) # store to buffer
+ addq t0, EISA_BYTE_OFFSET, t0 # increment I/O buffer
+ addl t3, 1, t3
+ and t3, 3, t3 # longwords only
+ bne t3, 10b # loop if not long aligned
+
+ // move aligned longwords
+
+20: srl a2, 2, t3 # longwords to move
+ beq t3, 40f # done moving longwords?
+
+ lda t11, EISA_LONG_OFFSET(zero) # longword stride in EISA space
+30: ldl t4, 0(a1) # fetch longword from memory
+ addl a1, 4, a1 # increment to next longword
+ subl t3, 1, t3 # decrement longwords to move
+ stl t4, EISA_LONG_LEN(t0) # store longword to EISA
+ addq t0, t11, t0 # increment EISA pointer
+ bne t3, 30b # while longwords remain
+
+40: and a2, 3, a2 # bytes remaining
+ //bis zero, zero, t3 # byte lane 0
+
+
+ // non-aligned and driblets move
+50: beq a2, 60f # copy while a2 > 0
+
+ ldq_u t1, 0(a1) # get quad surrounding byte
+ subl a2, 1, a2 # decrement count
+ extbl t1, a1, t1 # extract appropriate byte
+ addl a1, 1, a1 # increment buffer pointer
+ insbl t1, t3, t1 # get proper lane
+ stl t1, 0(t0) # store to buffer
+ addq t0, EISA_BYTE_OFFSET, t0 # increment I/O buffer
+ addl t3, 1, t3
+ and t3, 3, t3 # longwords only
+ br zero, 50b # end while
+
+60: mb
+
+ ret zero, (ra)
+
+//
+// source EISA alignment != destination memory alignment
+// move enough bytes to longword align the EISA destination
+// then move 32bit (longwords) reading unaligned data from memory
+// then move residual bytes
+//
+// t0 = superpage address of destination
+// a1 = virtual address of source
+// a2 = bytes to move
+// t9 = low 2 bits of EISA superpage address
+// t3 = low 2 bits of EISA QVA
+//
+
+70:
+ beq t9, 90f # branch if destination is longaligned
+
+// Move bytes until EISA src is at a longword boundary or bytes exhausted
+
+80: beq a2, 60b # while count > 0
+
+ ldq_u v0, 0(a1) # get byte
+ extbl v0, a1, v0 #
+ insbl v0, t3, v0 # get proper lane
+ stl v0, 0(t0) # store byte to EISA buffer
+ subl a2, 1, a2 # decrement count
+ addl a1, 1, a1 # next byte in buffer
+ addq t0, EISA_BYTE_OFFSET, t0 # next I/O address
+ addl t3, 1, t3 # next byte in lane
+ and t3, 3, t3 # longword lanes
+ bne t3, 80b # loop while not aligned
+
+ // aligned EISA source, unaligned memory destination
+
+90:
+ srl a2, 3, t3 # t3 = quadwords to move
+ beq t3, 110f # finish if no quadwords
+
+100:
+ ldq_u t1, 0(a1) # load low source quadword
+ ldq_u t2, 7(a1) # load high source quadword
+ extql t1, a1, t1 # extract low portion of quadword
+ extqh t2, a1, t2 # extract high portion of quadword
+ bis t1, t2, t1 # merge to get source quadword
+ stl t1, EISA_LONG_LEN(t0) # store low longword to EISA
+ lda a1, 8(a1) # increment to next source quadword
+ srl t1, 32, t1 # get high longword into position
+ subl t3, 1, t3 # decrement quadwords to move
+ stl t1, EISA_SECOND_LONG(t0) # store high longword
+ lda t0, EISA_QUAD_OFFSET(t0) # increment to next dest. quadword
+ bne t3, 100b # while quadwords to move
+
+110:
+ and a2, 7, a2 # bytes remaining to move
+ //bis zero, zero, t3 # byte line position of next byte
+ br zero, 50b # go back to byte mover
+
+120:
+ //
+ // This must be non I/O space access
+ //
+ br zero, RtlMoveMemory # Let Rtl routine handle move
+
+
+
+130:
+
+//
+// setup HAE
+//
+// a0 = QVA
+// a1 = source va
+// a2 = byte count
+// t0 = superpage bus address of destination
+// t3 = byte offset for destination (within a LONGWORD)
+// t4 = HAE index
+// t2 = upper bits of EISA superpage address
+//
+ lda t1, HalpHaeTable # get address of HAE table
+ ldiq t2, COMBO_IO # form upper bits of HAE
+ addl t4, t1, t1 # get address of new HAE value
+ sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
+ ldq_u t4, (t1) # get new HAE value
+ extbl t4, t1, t4 # ...
+
+#if DBG
+ // Note: the value in t4 should never be zero!
+ beq t4, 250f # br if new HAE value is zero!
+#endif
+
+ ldiq t1, HAE_PHYSICAL_BASEL # get base address of HAE register
+ or t1, t2, t1 # generate HAE superpage address
+
+ bis a1, zero, t6 # save a1, since SWAP_IRQL destroys it
+ bis a2, zero, t7 # save a2, since SWAP_IRQL destroys it
+ //
+ // Raise IRQL to device level to block other accesses to EISA memory
+ //
+ ldiq a0, DEVICE_LEVEL # get device level IRQL
+ SWAP_IRQL # raise IRQL to DEVICE_LEVEL
+ bis v0, zero, a0 # save original IRQL
+
+ bis t6, zero, a1 # restore a1
+ bis t7, zero, a2 # restore a2
+
+ //
+ // We will not bother to save the original HAE value. The value
+ // in the HAE must be zero... otherwise synchronization is broken.
+ // In debug mode, we will check the HAE however.
+ //
+#if DBG
+ ldl t8, (t1) # get original HAE value
+ bne t8, 250f # br if HAE is non-zero - error!
+#endif
+
+ stl t4, (t1) # write new HAE value
+ mb # force it out
+
+ //
+ // Now we can write the bytes to the EISA bus
+ //
+ // t8 = original HAE value (debug only)
+ // a0 = original IRQL
+ //
+ // t0 = superpage bus address of destination
+ // t1 = address of HAE register
+ // a1 = source va
+ // a2 = byte count
+ // t3 = byte offset of destination (within a LONGWORD)
+ //
+
+ ldiq t10, EISA_BITS_ONEZERO # mask for EISA address 1..0
+ and t0, t10, t9 # t9 holds EISA address bits 1..0
+ srl t9, EISA_BIT_SHIFT, t9 # position bits
+ and a1, 3, t10 # 1..0 of destination VA
+ xor t9, t10, t10 # compare alignment of src and dst
+ bne t10, 200f # use unaligned move if not aligned
+
+ // transfer can be done using longword fetch/store since the
+ // source and destination are sympathetically aligned
+
+ beq t9, 150f # br if dest is already longaligned
+
+// Move bytes until destination is at a longword boundary or bytes exhausted
+
+140: beq a2, 190f # while count > 0
+
+ ldq_u v0, 0(a1) # get quad surrounding byte
+ subl a2, 1, a2 # decrement count
+ extbl v0, a1, v0 # extract appropriate byte
+ addl a1, 1, a1 # increment buffer pointer
+ insbl v0, t3, v0 # get proper lane
+ stl v0, 0(t0) # store to buffer
+ addq t0, EISA_BYTE_OFFSET, t0 # increment I/O buffer
+ addl t3, 1, t3
+ and t3, 3, t3 # longwords only
+ bne t3, 140b # loop if not long aligned
+
+ // move aligned longwords
+
+150: srl a2, 2, t3 # longwords to move
+ beq t3, 170f # done moving longwords?
+
+ lda t11, EISA_LONG_OFFSET(zero) # longword stride in EISA space
+160: ldl t4, 0(a1) # fetch longword from memory
+ addl a1, 4, a1 # increment to next longword
+ subl t3, 1, t3 # decrement longwords to move
+ stl t4, EISA_LONG_LEN(t0) # store longword to EISA
+ addq t0, t11, t0 # increment EISA pointer
+ bne t3, 160b # while longwords remain
+
+170: and a2, 3, a2 # bytes remaining
+ //bis zero, zero, t3 # byte lane 0
+
+
+ // non-aligned and driblets move
+180: beq a2, 190f # copy while a2 > 0
+
+ ldq_u v0, 0(a1) # get quad surrounding byte
+ subl a2, 1, a2 # decrement count
+ extbl v0, a1, v0 # extract appropriate byte
+ addl a1, 1, a1 # increment buffer pointer
+ insbl v0, t3, v0 # get proper lane
+ stl v0, 0(t0) # store to buffer
+ addq t0, EISA_BYTE_OFFSET, t0 # increment I/O buffer
+ addl t3, 1, t3
+ and t3, 3, t3 # longwords only
+ br zero, 180b # end while
+
+190:
+ //
+ // Restore HAE before exiting
+ //
+ stl zero, (t1) # restore original HAE value
+ mb # force it out + previous writes
+
+ //
+ // Lower IRQL, original IRQL in a0
+ //
+ SWAP_IRQL # restore original IRQL
+
+ ret zero, (ra)
+
+//
+// source EISA alignment != destination memory alignment
+// move enough bytes to longword align the EISA destination
+// then move 32bit (longwords) reading unaligned data from memory
+// then move residual bytes
+//
+// t0 = superpage address of destination
+// a1 = virtual address of source
+// a2 = bytes to move
+// t9 = low 2 bits of EISA superpage address
+// t3 = low 2 bits of EISA QVA
+//
+
+200:
+ beq t9, 220f # branch if destination is longaligned
+
+// Move bytes until EISA src is at a longword boundary or bytes exhausted
+
+210: beq a2, 190b # while count > 0
+
+ ldq_u v0, 0(a1) # get byte
+ extbl v0, a1, v0 #
+ insbl v0, t3, v0 # get proper lane
+ stl v0, 0(t0) # store byte to EISA buffer
+ subl a2, 1, a2 # decrement count
+ addl a1, 1, a1 # next byte in buffer
+ addq t0, EISA_BYTE_OFFSET, t0 # next I/O address
+ addl t3, 1, t3 # next byte in lane
+ and t3, 3, t3 # longword lanes
+ bne t3, 210b # loop while not aligned
+
+ // aligned EISA source, unaligned memory destination
+
+220:
+ srl a2, 3, t3 # t3 = quadwords to move
+ beq t3, 240f # finish if no quadwords
+
+230:
+ ldq_u v0, 0(a1) # load low source quadword
+ ldq_u t2, 7(a1) # load high source quadword
+ extql v0, a1, v0 # extract low portion of quadword
+ extqh t2, a1, t2 # extract high portion of quadword
+ bis v0, t2, v0 # merge to get source quadword
+ stl v0, EISA_LONG_LEN(t0) # store low longword to EISA
+ lda a1, 8(a1) # increment to next source quadword
+ srl v0, 32, v0 # get high longword into position
+ subl t3, 1, t3 # decrement quadwords to move
+ stl v0, EISA_SECOND_LONG(t0) # store high longword
+ lda t0, EISA_QUAD_OFFSET(t0) # increment to next dest. quadword
+ bne t3, 230b # while quadwords to move
+
+240:
+ and a2, 7, a2 # bytes remaining to move
+ //bis zero, zero, t3 # byte line position of next byte
+ br zero, 180b # go back to byte mover
+
+#if DBG
+250:
+ // New HAE value is zero!
+ BREAK_DEBUG_STOP
+ ldil a0, BAD_QVA
+ jsr t12, KeBugCheck # crash if bad HAE index
+#endif
+
+
+ .end WRITE_REGISTER_BUFFER_UCHAR
+
+
+
+ LEAF_ENTRY(WRITE_REGISTER_BUFFER_USHORT)
+
+/*++
+
+Routine Description:
+
+ Writes to the specified buffer address. This routine only works
+ with EISA memory space, since there are no REGISTER buffers in
+ COMBO space on Jensen.
+
+ Both the input buffer and output buffer should be word aligned.
+
+Arguments:
+
+ a0 QVA of destination buffer.
+ a1 VA of source buffer in memory.
+ a2 Number of bytes to move (Count).
+
+
+Return Value:
+
+ None
+
+--*/
+
+ beq a2, 30f # leave if nothing to do
+ srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
+ and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
+ xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
+ and a0, 3, t3 # get byte within longword
+ bne t1, 40f # br if not a bus address
+
+ ldah t0, QVA_CONTROL(zero) # get mask clear bits
+ and t2, 3, t4 # get HAE index
+ bic a0, t0, t0 # clear QVA control bits a0<63:25>
+
+ ldiq t2, EISA_MEMORY # form upper bits of PA
+ sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
+ sll t2, IO_HI_SHIFT, t2 # shift upper bits into position
+ or t0, t2, t0 # generate superpage address
+ or t0, EISA_WORD_LEN, t0 # or in the WORD byte enables
+
+ //
+ // Note - at this point we know bits t0<63:25> = 0
+ //
+ // Check if we have to load the HAE with a non-zero value. This
+ // is considered non-standard, but it is supported. Loading the HAE
+ // requires additional synchronization.
+ //
+ bne t4, 100f # br if HAE has to be set up
+
+20:
+ ldq_u t1, 0(a1) # get quad surrounding word
+ subl a2, 1, a2 # decrement count
+ extwl t1, a1, t1 # extract appropriate word
+ addl a1, 2, a1 # increment buffer pointer
+ inswl t1, t3, t1 # get proper lane
+ stl t1, 0(t0) # store to buffer
+ addq t0, EISA_SHORT_OFFSET, t0 # increment I/O buffer
+ addl t3, 2, t3
+ and t3, 3, t3 # longwords only
+ bne a2, 20b # end while
+
+30:
+ ret zero, (ra)
+
+40:
+ //
+ // This must be non I/O space access
+ //
+ sll a2, 1, a2 # convert word count to byte count
+ br zero, RtlMoveMemory # Let Rtl routine handle move
+
+
+100:
+
+//
+// setup HAE
+//
+// a0 = QVA of destination
+// a1 = source va
+// a2 = word count
+// t0 = superpage bus address of destination
+// t3 = byte offset for destination (within a LONGWORD)
+// t4 = HAE index
+// t2 = upper bits of EISA superpage address
+//
+
+ lda t1, HalpHaeTable # get address of HAE table
+ ldiq t2, COMBO_IO # form upper bits of HAE
+ addl t4, t1, t1 # get address of new HAE value
+ sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
+ ldq_u t4, (t1) # get new HAE value
+ extbl t4, t1, t4 # ...
+
+#if DBG
+ // Note: the value in t4 should never be zero!
+ beq t4, 150f # br if new HAE value is zero!
+#endif
+
+ ldiq t1, HAE_PHYSICAL_BASEL # get base address of HAE register
+ or t1, t2, t1 # generate HAE superpage address
+
+ bis a1, zero, t6 # save a1, since SWAP_IRQL destroys it
+ bis a2, zero, t7 # save a2, since SWAP_IRQL destroys it
+ //
+ // Raise IRQL to device level to block other accesses to EISA memory
+ //
+ ldiq a0, DEVICE_LEVEL # get device level IRQL
+ SWAP_IRQL # raise IRQL to DEVICE_LEVEL
+ bis v0, zero, a0 # save original IRQL
+
+ //
+ // We will not bother to save the original HAE value. The value
+ // in the HAE must be zero... otherwise synchronization is broken.
+ // In debug mode, we will check the HAE however.
+ //
+#if DBG
+ ldl t8, (t1) # get original HAE value
+ bne t8, 150f # br if HAE is non-zero - error!
+#endif
+
+ stl t4, (t1) # write new HAE value
+ mb # force it out
+
+ //
+ // Now we can read the words from the EISA bus
+ //
+ // t8 = original HAE value (debug only)
+ // a0 = original IRQL
+ //
+ // t0 = superpage bus address of source
+ // t1 = address of HAE register
+ // t6 = destination va
+ // t7 = word count
+ // t3 = byte offset for source (within a LONGWORD)
+ //
+
+120:
+ ldq_u v0, 0(t6) # get quad surrounding word
+ subl t7, 1, t7 # decrement count
+ extwl v0, t6, v0 # extract appropriate word
+ addl t6, 2, t6 # increment buffer pointer
+ inswl v0, t3, v0 # get proper lane
+ stl v0, 0(t0) # store to buffer
+ addq t0, EISA_SHORT_OFFSET, t0 # increment I/O buffer
+ addl t3, 2, t3
+ and t3, 3, t3 # longwords only
+ bne t7, 120b # end while
+
+ //
+ // Restore HAE before exiting
+ //
+ stl zero, (t1) # restore original HAE value
+ mb # force it out
+
+ //
+ // Lower IRQL, original IRQL in a0
+ //
+ SWAP_IRQL # restore original IRQL
+
+ ret zero, (ra)
+
+#if DBG
+150:
+ // New HAE value is zero!
+ BREAK_DEBUG_STOP
+ ldil a0, BAD_QVA
+ jsr t12, KeBugCheck # crash if bad HAE index
+#endif
+
+
+ .end WRITE_REGISTER_BUFFER_USHORT
+
+
+ LEAF_ENTRY(WRITE_REGISTER_BUFFER_ULONG)
+
+/*++
+
+Routine Description:
+
+ Writes to the specified buffer address. This routine only works
+ with EISA memory space, since there are no REGISTER buffers in
+ COMBO space on Jensen.
+
+ Both the input buffer and output buffer should be longword aligned.
+
+Arguments:
+
+ a0 QVA of destination buffer in I/O space.
+ a1 VA of source buffer in memory.
+ a2 Number of longwords to move (Count).
+
+
+Return Value:
+
+ None
+
+--*/
+
+
+ beq a2, 30f # leave if nothing to do
+ srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
+ and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
+ xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
+ bne t1, 40f # br if not a bus address
+
+ ldah t0, QVA_CONTROL(zero) # get mask clear bits
+ and t2, 3, t4 # get HAE index
+ bic a0, t0, t0 # clear QVA control bits a0<63:25>
+
+ ldiq t2, EISA_MEMORY # form upper bits of PA
+ sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
+ sll t2, IO_HI_SHIFT, t2 # shift upper bits into position
+ or t0, t2, t0 # generate superpage address
+ or t0, EISA_LONG_LEN, t0 # or in the byte enables
+
+ //
+ // Note - at this point we know bits t0<63:25> = 0
+ //
+ // Check if we have to load the HAE with a non-zero value. This
+ // is considered non-standard, but it is supported. Loading the HAE
+ // requires additional synchronization.
+ //
+ bne t4, 100f # br if HAE has to be set up
+
+20:
+ ldl t1, 0(a1) # get longword
+ subl a2, 1, a2 # decrement count
+ addl a1, 4, a1 # increment buffer pointer
+ stl t1, 0(t0) # store to buffer
+ addq t0, EISA_LONG_OFFSET, t0 # increment I/O buffer
+ bne a2, 20b # end while
+
+30:
+ ret zero, (ra)
+
+40:
+ //
+ // This must be non I/O space access
+ //
+ s4addl a2, zero, a2 # convert longword count to byte count
+ br zero, RtlMoveMemory # Let Rtl routine handle move
+
+
+100:
+
+//
+// setup HAE
+//
+// a0 = QVA of destination
+// a1 = source va
+// a2 = longword count
+// t0 = superpage bus address of destination
+// t4 = HAE index
+// t2 = upper bits of EISA superpage address
+//
+
+ lda t1, HalpHaeTable # get address of HAE table
+ ldiq t2, COMBO_IO # form upper bits of HAE
+ addl t4, t1, t1 # get address of new HAE value
+ sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
+ ldq_u t4, (t1) # get new HAE value
+ extbl t4, t1, t4 # ...
+
+#if DBG
+ // Note: the value in t4 should never be zero!
+ beq t4, 150f # br if new HAE value is zero!
+#endif
+
+ ldiq t1, HAE_PHYSICAL_BASEL # get base address of HAE register
+ or t1, t2, t1 # generate HAE superpage address
+
+ bis a1, zero, t6 # save a1, since SWAP_IRQL destroys it
+ bis a2, zero, t7 # save a2, since SWAP_IRQL destroys it
+ //
+ // Raise IRQL to device level to block other accesses to EISA memory
+ //
+ ldiq a0, DEVICE_LEVEL # get device level IRQL
+ SWAP_IRQL # raise IRQL to DEVICE_LEVEL
+ bis v0, zero, a0 # save original IRQL
+
+ //
+ // We will not bother to save the original HAE value. The value
+ // in the HAE must be zero... otherwise synchronization is broken.
+ // In debug mode, we will check the HAE however.
+ //
+#if DBG
+ ldl t8, (t1) # get original HAE value
+ bne t8, 150f # br if HAE is non-zero - error!
+#endif
+
+ stl t4, (t1) # write new HAE value
+ mb # force it out
+
+ //
+ // Now we can read the words from the EISA bus
+ //
+ // t8 = original HAE value (debug only)
+ // a0 = original IRQL
+ //
+ // t0 = superpage bus address of source
+ // t1 = address of HAE register
+ // t6 = destination va
+ // t7 = word count
+ // t3 = byte offset for source (within a LONGWORD)
+ //
+
+120:
+ ldl v0, 0(t6) # get longword
+ subl t7, 1, t7 # decrement count
+ addl t6, 4, t6 # increment buffer pointer
+ stl v0, 0(t0) # store to buffer
+ addq t0, EISA_LONG_OFFSET, t0 # increment I/O buffer
+ bne t7, 120b # end while
+
+ //
+ // Restore HAE before exiting
+ //
+ stl zero, (t1) # restore original HAE value
+ mb # force it out
+
+ //
+ // Lower IRQL, original IRQL in a0
+ //
+ SWAP_IRQL # restore original IRQL
+
+ ret zero, (ra)
+
+#if DBG
+150:
+ // New HAE value is zero!
+ BREAK_DEBUG_STOP
+ ldil a0, BAD_QVA
+ jsr t12, KeBugCheck # crash if bad HAE index
+#endif
+
+
+ .end WRITE_REGISTER_BUFFER_ULONG
+
diff --git a/private/ntos/nthals/hal0jens/alpha/jxiouser.c b/private/ntos/nthals/hal0jens/alpha/jxiouser.c
new file mode 100644
index 000000000..8ab422c06
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/jxiouser.c
@@ -0,0 +1,971 @@
+#if defined (JENSEN)
+
+/*++
+
+Copyright (c) 1992 Digital Equipment Corporation
+
+Module Name:
+
+ jxioacc.c
+
+Abstract:
+
+ This module contains the Jensen I/O space access routines for user mode
+ mapped addresses.
+
+ The READ_PORT_Uxxx MACROs simply call the equivalent READ_REGISTER_Uxxx
+ routine. Similarly, the WRITE_PORT_Uxxx MACROs call the equivalent
+ WRITE_REGISTER_Uxxx routines. Since Jensen uses 64 bit super pages for
+ Virtual I/O, and that super pages are only accessable through kernel
+ mode, these routines here will decode a QVA and do the access, but
+ through normal translations.
+
+ All these routines ensure that the calling argument is a QVA, such
+ as would be returned by the wrapper around MmMapIoSpace - this should
+ have QVA_ENABLE set. They determine which type of shift should be
+ used, based on the next bit in the longword.
+
+ Note that the argument is declared as PUCHAR or PUSHORT or
+ whatever, even though it really is a QUASI_VIRTUAL_ADDRESS. This
+ is for driver compatibility: all the drivers out there get a
+ PVOID from MmMapIoSpace, then cast it to PU* before calling these
+ routines. If we insisted on declaring them correctly, we would
+ have to change all the drivers, which is what we are trying to avoid.
+
+ Lane shifting: the Jensen box will not do lane shifting in EISA
+ space. That means that for access shorter than a longword, the
+ data will NOT show up in the lowest bit position, but will be in
+ the byte/word that it would have started in. For longwords, the
+ value will show up on the data path correctly. For, say, the 3rd
+ byte in a word, a longword would be returned, and bytes 0, 1 and 3
+ would be garbage, and the value in byte 2 would be the one you
+ wanted. The same applies for writing: a longword will always be
+ sent out onto the bus, and we must move the valid data byte into
+ the correct position, and set the byte enables to say which byte
+ to use. Note that what you cannot do is leave the byte in the
+ lowest position, and set the byte enable to the lowest byte,
+ because this would generate an unaligned longword access, which
+ the chip cannot handle.
+
+ So, for bytes, the access must be an aligned longword, with byte
+ enables set to indicate which byte to get/set, and the byte moved
+ to/from the desired position within the longword. Similarly for
+ shorts. Tribytes are not supported.
+
+ Lane shifting is not an issue for accessing the Combo chip, which
+ only allows byte accesses, and for which the data is always moved
+ to the low 8 bits of the HBUS data longword, according to the spec.
+
+ Performance: If the buffer routines get used alot, something we
+ could do to improve performance would be to send four byte or two
+ shorts out to the bus at a time (or get them). This would work
+ because the PIC queries the device about the size of transfer that
+ it can accept (or the device rejects a transfer that it cannot
+ handle) and parcels the data out in correct size chunks.
+
+Author:
+
+ Rod N. Gamache (DEC) 5-May-1992
+ Miche Baker-Harvey (miche) 21-May-1992
+ Jeff McLeman (DEC) 30-Jul-1992
+
+Revision History:
+
+--*/
+// Include files
+
+#include "halp.h"
+#include "jnsndef.h"
+
+
+UCHAR
+READ_REGISTER_UCHAR(
+ volatile PUCHAR Register
+ )
+
+/*++
+
+Routine Description:
+
+ Read from the specified register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the register in EISA I/O space.
+
+Return Value:
+
+ Returns the value read from the specified register address.
+
+--*/
+
+{
+ ULONG mv; // Local value
+ ULONG byte; // which byte we want
+ volatile PULONG ma; // Local address
+
+ HalpMb;
+
+ //
+ // If it's an EISA address, use EISA shifts, byte enables
+ //
+
+ if (IS_EISA_QVA(Register)) {
+
+ //
+ // Determine which byte it is that we want.
+ //
+
+ byte = (ULONG)Register & 0x3;
+
+ //
+ // Shift the virtual address into position, and indicate that
+ // we want a byte.
+ //
+ // The desired byte enable is set automatically because the
+ // Jensen designers picked values which correspond exactly
+ // to the actual byte addresses
+ //
+
+ ma = (volatile PULONG)
+ (EISA_BYTE_LEN | ((ULONG)Register << EISA_BIT_SHIFT));
+
+ //
+ // Get the longword value, which will only have one valid byte
+ //
+
+ mv = *ma;
+
+ //
+ // Extract out and return the desired byte
+ // The compiler should convert the multiplication
+ //
+
+ return((UCHAR)(mv >> (byte * 8)));
+
+ }
+
+ //
+ // If it's a Combo Chip address, use those shifts, byte enables
+ //
+
+ if (IS_COMBO_QVA(Register)) {
+ return ((UCHAR)(*(volatile PULONG )(COMBO_BYTE_LEN |
+ ((ULONG)Register << COMBO_BIT_SHIFT))));
+ }
+
+ //
+ // It's not a valid QVA
+ //
+
+ KeBugCheck("Invalid QVA in READ_REGISTER_UCHAR\n");
+}
+
+
+
+USHORT
+READ_REGISTER_USHORT(
+ volatile PUSHORT Register
+ )
+
+/*++
+
+Routine Description:
+
+ Read from the specified Register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the register in EISA I/O space.
+
+Return Value:
+
+ Returns the value read from the specified register address.
+
+--*/
+
+{
+ ULONG mv, word; // Local value and word we want
+ volatile PULONG ma; // Local address
+
+ //
+ // This works as long as we don't want the fourth short!
+ //
+ ASSERT(((ULONG)Register & 0x3) != 0x3);
+
+ //
+ // If it's an EISA address, use EISA shifts, word enables
+ //
+
+ if (IS_EISA_QVA(Register)) {
+
+ //
+ // Determine which word it is that we want.
+ //
+
+ word = (ULONG)Register & 0x3;
+
+ //
+ // Shift the virtual address into position, and indicate that
+ // we want a word.
+ //
+ // The desired word enable is set automatically because the
+ // Jensen designers picked values which correspond exactly
+ // to the actual word addresses
+ //
+
+ ma = (volatile PULONG)
+ (EISA_WORD_LEN | ((ULONG)Register << EISA_BIT_SHIFT));
+
+ //
+ // Get the longword value, which will only have one valid word
+ //
+
+ mv = *ma;
+
+ //
+ // Extract out and return the desired word
+ // The compiler should convert the multiplication
+ //
+
+ return((USHORT)(mv >> (8 * word)));
+
+ }
+
+ //
+ // USHORT operations are not supported on the combo chip
+ //
+
+ if (IS_COMBO_QVA(Register)) {
+
+ KeBugCheck("Invalid Combo QVA in READ_REGISTER_USHORT\n");
+ }
+
+ KeBugCheck("Invalid QVA in READ_REGISTER_USHORT\n");
+}
+
+
+ULONG
+READ_REGISTER_ULONG(
+ volatile PULONG Register
+ )
+
+/*++
+
+Routine Description:
+
+ Read from the specified register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the register in EISA I/O space.
+
+Return Value:
+
+ Returns the value read from the specified register address.
+
+--*/
+
+{
+
+ //
+ // We are assuming that the longword is aligned
+ //
+ ASSERT(((ULONG)Register & 0x3) == 0x0);
+
+ if (IS_EISA_QVA(Register)) {
+
+ HalpMb;
+ return (*(volatile PULONG)(EISA_LONG_LEN |
+ ((ULONG)Register << EISA_BIT_SHIFT)));
+
+ }
+
+ //
+ // ULONG operations are not supported on the combo chip
+ //
+
+ if (IS_COMBO_QVA(Register)) {
+
+ KeBugCheck("Invalid Combo QVA in READ_REGISTER_ULONG\n");
+ }
+
+ KeBugCheck("Invalid QVA in READ_REGISTER_ULONG\n");
+}
+
+
+VOID
+WRITE_REGISTER_UCHAR(
+ volatile PUCHAR Register,
+ UCHAR Value
+ )
+
+/*++
+
+Routine Description:
+
+ Write to the specified register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the register in EISA I/O space.
+ Value - The value to be written to the register.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG mv; // local copy of value for shifting
+ ULONG byte; // the byte position requested
+
+ //
+ // If it's an EISA address, use EISA shifts, byte enables
+ //
+
+ if (IS_EISA_QVA(Register)) {
+
+ //
+ // Determine which byte it is that we want.
+ //
+
+ byte = (ULONG)Register & 0x3;
+
+ //
+ // Move value into appropriate byte position in longword
+ // The compiler should convert the multiplication
+ //
+
+ mv = (ULONG)(Value << (8 * byte));
+
+ //
+ // The address is long aligned and the byte enables set
+ // automagically by the way the Jensen physical map is set
+ //
+ *(volatile PULONG)(EISA_BYTE_LEN |
+ ((ULONG)Register << EISA_BIT_SHIFT)) = mv;
+ HalpMb;
+ return;
+ }
+
+ //
+ // If it's a Combo Chip address, use those shifts, byte enables
+ // No lane shifting is required for the Combo chip.
+ //
+
+ if (IS_COMBO_QVA(Register)) {
+
+ *(volatile PULONG)(COMBO_BYTE_LEN |
+ ((ULONG)Register << COMBO_BIT_SHIFT)) = Value;
+ HalpMb;
+ return;
+ }
+
+ //
+ // It's not a valid QVA
+ //
+
+ KeBugCheck("Invalid QVA in WRITE_REGISTER_UCHAR\n");
+}
+
+
+VOID
+WRITE_REGISTER_USHORT(
+ volatile PUSHORT Register,
+ USHORT Value
+ )
+
+/*++
+
+Routine Description:
+
+ Write to the specified register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the register in EISA I/O space.
+ Value - The value to be written to the register.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG mv; // local copy of value for shifting
+ UCHAR word; // the word position requested
+
+ //
+ // This works as long as we don't want the fourth short!
+ //
+ ASSERT(((ULONG)Register & 0x3) != 0x3);
+
+ //
+ // If it's an EISA address, use EISA shifts, word enables
+ //
+
+ if (IS_EISA_QVA(Register)) {
+
+
+ //
+ // Determine which word it is that we want.
+ //
+
+ word = (ULONG)Register & 0x3;
+
+ //
+ // Move value into appropriate word position in longword
+ // The compiler should convert the multiplication
+ //
+
+ mv = (ULONG)(Value << (8 * word));
+
+ //
+ // The address is long aligned and the word enables set
+ // automagically by the way the Jensen physical map is set
+ //
+
+ *(volatile PULONG)(EISA_WORD_LEN |
+ ((ULONG)Register << EISA_BIT_SHIFT)) = mv;
+ HalpMb;
+ return;
+ }
+
+ //
+ // USHORT operations are not supported on the combo chip
+ //
+
+ if (IS_COMBO_QVA(Register)) {
+
+ KeBugCheck("Invalid Combo QVA in WRITE_REGISTER_USHORT\n");
+ }
+
+ KeBugCheck("Invalid QVA in WRITE_REGISTER_USHORT\n");
+}
+
+
+VOID
+WRITE_REGISTER_ULONG(
+ volatile PULONG Register,
+ ULONG Value
+ )
+
+/*++
+
+Routine Description:
+
+ Write to the specified register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the register in EISA I/O space.
+ Value - The value to be written to the register.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ //
+ // We are assuming that the longword is aligned
+ //
+ ASSERT(((ULONG)Register & 0x3) == 0x0);
+
+ if (IS_EISA_QVA(Register)) {
+
+ *(volatile PULONG)(EISA_LONG_LEN |
+ ((ULONG)Register << EISA_BIT_SHIFT)) = Value;
+ HalpMb;
+ return;
+ }
+
+ //
+ // ULONG operations are not supported on the combo chip
+ //
+
+ if (IS_COMBO_QVA(Register)) {
+
+ KeBugCheck("Invalid Combo QVA in WRITE_REGISTER_ULONG\n");
+ }
+
+ KeBugCheck("Invalid QVA in WRITE_REGISTER_ULONG\n");
+}
+
+
+
+VOID
+READ_PORT_BUFFER_UCHAR(
+ volatile PUCHAR Port,
+ PUCHAR Buffer,
+ ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Read from the specified port buffer address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port in EISA space.
+ Buffer - the address of the buffer in memory to copy the data to.
+ Count - the number of bytes to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG i, mv;
+ volatile PULONG ma;
+ ULONG byte;
+
+ HalpMb;
+ if (IS_EISA_QVA(Port)) {
+
+ //
+ // Shift the virtual address into position, and indicate that
+ // we want a byte.
+ //
+ // The desired byte enable is set automatically because the
+ // Jensen designers picked values which correspond exactly
+ // to the actual byte addresses
+ //
+
+ ma = (volatile PULONG)
+ (EISA_BYTE_LEN | ((ULONG)Port << EISA_BIT_SHIFT));
+
+ for ( i = 0 ; i < Count ; i++) {
+
+ //
+ // Determine which byte it is that we want.
+ //
+
+ byte = (ULONG)ma & (0x3 << EISA_BIT_SHIFT);
+
+ //
+ // Get the longword value, which will only have one valid byte
+ //
+
+ mv = *ma;
+
+ //
+ // Extract out the desired byte
+ // The compiler should convert the multiplication
+ //
+
+ *Buffer++ = ((UCHAR)(mv >> (8 * byte)));
+
+
+ }
+
+ } else if (IS_COMBO_QVA(Port)) {
+
+ ma = (volatile PULONG) (COMBO_BYTE_LEN |
+ ((ULONG)Port << COMBO_BIT_SHIFT));
+ for ( i = 0 ; i < Count ; i++) {
+ *Buffer++ = *ma;
+ ma = (PULONG)((PUCHAR)ma + COMBO_BYTE_OFFSET);
+ }
+
+ } else {
+
+ //
+ // Invalid QVA
+ //
+ KeBugCheck("Invalid QVA in READ_PORT_BUFFER_UCHAR\n");
+ }
+}
+
+
+VOID
+READ_PORT_BUFFER_USHORT(
+ volatile PUSHORT Port,
+ PUSHORT Buffer,
+ ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Read from the specified port buffer address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port in EISA space.
+ Buffer - the address of the buffer in memory to copy the data to.
+ Count - the number of shorts to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG i, mv;
+ volatile PULONG ma;
+ ULONG word;
+
+ //
+ // The code gets really ugly if shorts are not aligned!
+ //
+ ASSERT(((ULONG)Port & 0x1) == 0x0);
+
+ if (IS_EISA_QVA(Port)) {
+
+ HalpMb;
+
+ //
+ // Shift the virtual address into position, and indicate that
+ // we want a word.
+ //
+ // The desired word enable is set automatically because the
+ // Jensen designers picked values which correspond exactly
+ // to the actual word addresses
+ //
+
+ ma = (volatile PULONG)
+ (EISA_WORD_LEN | ((ULONG)Port << EISA_BIT_SHIFT));
+
+ for ( i = 0 ; i < Count ; i++) {
+
+ //
+ // Determine which word it is that we want; the low
+ // order bit cannot be set.
+ //
+
+ word = (ULONG)ma & (0x2 << EISA_BIT_SHIFT);
+
+ //
+ // Get the longword value, which will only have one valid word
+ //
+
+ mv = *ma;
+
+ //
+ // Extract out the desired word
+ // The compiler should convert the multiplication
+ //
+
+ *Buffer++ = ((USHORT)(mv >> (8 * word)));
+
+
+ }
+ return;
+ }
+
+ //
+ // USHORT operations are not supported on the combo chip
+ //
+
+ if (IS_COMBO_QVA(Port)) {
+
+ KeBugCheck("Invalid Combo QVA in READ_PORT_BUFFER_USHORT\n");
+ }
+
+ KeBugCheck("Invalid QVA in READ_PORT_BUFFER_USHORT\n");
+
+}
+
+
+VOID
+READ_PORT_BUFFER_ULONG(
+ volatile PULONG Port,
+ PULONG Buffer,
+ ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Read from the specified port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port in EISA space.
+ Buffer - the address of the buffer in memory to copy the data to.
+ Count - the number of longs to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG i;
+ volatile PULONG ptr;
+
+ //
+ // We are assuming that the longword is aligned
+ //
+ ASSERT(((ULONG)Port & 0x3) == 0x0);
+
+ if (IS_EISA_QVA(Port)) {
+ HalpMb;
+ ptr = (volatile ULONG *) (EISA_LONG_LEN |
+ ((ULONG)Port << EISA_BIT_SHIFT));
+ for ( i = 0 ; i < Count ; i++) {
+ *Buffer++ = *ptr;
+ }
+ return;
+ }
+
+ //
+ // ULONG operations are not supported on the combo chip
+ //
+
+ if (IS_COMBO_QVA(Port)) {
+
+ KeBugCheck("Invalid Combo QVA in READ_PORT_BUFFER_ULONG\n");
+ }
+
+ KeBugCheck("Invalid QVA in READ_PORT_BUFFER_ULONG\n");
+
+}
+
+
+VOID
+WRITE_PORT_BUFFER_UCHAR(
+ volatile PUCHAR Port,
+ PUCHAR Buffer,
+ ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Write to the specified port buffer address.
+
+ If the Port and Buffer addresses are aligned with respect to each
+ other, we don't have to do a shift on each move - which would be a
+ bit faster. On the other hand, no one calls this routine, and it
+ would be more complicated to handle the two cases, so let it be.
+
+Arguments:
+
+ Port - Supplies a pointer to the port in EISA space.
+ Buffer - the address of the buffer in memory to copy the data from.
+ Count - the number of bytes to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG i, mv;
+ volatile PULONG ma;
+ ULONG byte;
+
+
+ if (IS_EISA_QVA(Port)) {
+
+ ma = (volatile PULONG) (EISA_BYTE_LEN |
+ ((ULONG)Port << EISA_BIT_SHIFT));
+
+ for ( i = 0 ; i < Count ; i++) {
+
+ //
+ // Determine which byte it is that we want to write to
+ // This changes with every byte written.
+ //
+
+ byte = (ULONG)ma & (0x3 << EISA_BIT_SHIFT);
+
+ //
+ // Move value into appropriate byte position in longword,
+ // and advance our position in the buffer.
+ // The compiler should convert the multiplication
+ //
+
+ mv = (ULONG)(*Buffer << (8 * byte));
+ Buffer++;
+
+ //
+ // send the lane shifted value to the EISA bus
+ //
+
+ *ma = mv;
+
+ }
+
+ HalpMb;
+ return;
+ }
+
+ if (IS_COMBO_QVA(Port)) {
+
+ ma = (volatile PULONG) (COMBO_BYTE_LEN |
+ ((ULONG)Port << COMBO_BIT_SHIFT));
+ for ( i = 0 ; i < Count ; i++) {
+ *ma = *Buffer++;
+ ma = (PULONG)((PUCHAR)ma + COMBO_BYTE_OFFSET);
+ }
+ HalpMb;
+ return;
+
+ }
+
+ //
+ // Invalid QVA
+ //
+ KeBugCheck("Invalid QVA in WRITE_PORT_BUFFER_UCHAR\n");
+
+}
+
+
+VOID
+WRITE_PORT_BUFFER_USHORT(
+ volatile PUSHORT Port,
+ PUSHORT Buffer,
+ ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Write to the specified port buffer address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port in EISA space.
+ Buffer - the address of the buffer in memory to copy the data from.
+ Count - the number of shorts to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG i, mv;
+ volatile PULONG ma;
+ ULONG word;
+
+ //
+ // The code gets really ugly if shorts are not aligned!
+ //
+ ASSERT(((ULONG)Port & 0x1) == 0x0);
+
+ if (IS_EISA_QVA(Port)) {
+
+ ma = (volatile PULONG) (EISA_WORD_LEN |
+ ((ULONG)Port << EISA_BIT_SHIFT));
+
+ for ( i = 0 ; i < Count ; i++) {
+
+ //
+ // Determine which word it is that we want to write to
+ // This changes with every word written.
+ //
+
+ word = (ULONG)ma & (0x2 << EISA_BIT_SHIFT);
+
+ //
+ // Move value into appropriate word position in longword,
+ // and advance our position in the buffer.
+ // The compiler should convert the multiplication
+ //
+
+ mv = (ULONG)(*Buffer++ << (8 * word));
+
+ //
+ // send the lane shifted value to the EISA bus
+ //
+
+ *ma = mv;
+
+ }
+
+ HalpMb;
+ return;
+
+ }
+
+ //
+ // USHORT operations are not supported on the combo chip
+ //
+
+ if (IS_COMBO_QVA(Port)) {
+
+ KeBugCheck("Invalid Combo QVA in WRITE_PORT_BUFFER_USHORT\n");
+ }
+
+ KeBugCheck("Invalid QVA in WRITE_PORT_BUFFER_USHORT\n");
+
+}
+
+
+VOID
+WRITE_PORT_BUFFER_ULONG(
+ volatile PULONG Port,
+ PULONG Buffer,
+ ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Write to teh specified port buffer address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port in EISA space.
+ Buffer - the address of the buffer in memory to copy the data from.
+ Count - the number of longs to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG i;
+ volatile PULONG ptr;
+
+ //
+ // We are assuming that the port address is long aligned
+ //
+ ASSERT(((ULONG)Port & 0x3) == 0x0);
+
+ if (IS_EISA_QVA(Port)) {
+ ptr = (volatile ULONG *) (EISA_LONG_LEN |
+ ((ULONG)Port << EISA_BIT_SHIFT));
+ for ( i = 0 ; i < Count ; i++) {
+ *ptr = *Buffer++;
+ }
+ HalpMb;
+ return;
+ }
+
+ //
+ // ULONG operations are not supported on the combo chip
+ //
+
+ if (IS_COMBO_QVA(Port)) {
+
+ KeBugCheck("Invalid Combo QVA in WRITE_PORT_BUFFER_ULONG\n");
+ }
+
+ KeBugCheck("Invalid QVA in WRITE_PORT_BUFFER_ULONG\n");
+
+}
+#endif // JENSEN
diff --git a/private/ntos/nthals/hal0jens/alpha/jxirql.h b/private/ntos/nthals/hal0jens/alpha/jxirql.h
new file mode 100644
index 000000000..c40492d11
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/jxirql.h
@@ -0,0 +1,133 @@
+//++
+//
+// Module Name:
+//
+// jxirql.h
+//
+// Description:
+//
+// The platform-specific interrupt tables, defined by the HAL
+// and used by the PAL to define interrupt synchronization
+// and prioritization.
+//
+// Author:
+//
+// Joe Notarangelo, generated via VB program IRQL
+//
+// Environment
+//
+// HAL private data structures
+//
+// Revision History:
+//
+// Joe Notarangelo 8-Jul-1993
+// Edited this file by hand to:
+// a. Create appropriate mask values for the performance counter
+// interrupts
+// b. Disable keyboard and serial interrupts by default, they
+// will now be enabled/disabled by the standard HAL interfaces
+//
+//--
+
+//
+// Interrupt Enable Table
+//
+//
+// III III
+// RRR RRRC PPDA
+// QQQ QQQR CCPP
+// 543 210D 10CC
+//
+
+ULONG HalpIET[] = {
+ 0x2f3 , // irql 0
+ 0x2f2 , // irql 1
+ 0x2f0 , // irql 2
+ 0x2b0 , // irql 3
+ 0x2b0 , // irql 4
+ 0x290 , // irql 5
+ 0x280 , // irql 6
+ 0x000 // irql 7
+};
+
+//
+// Interrupt Synchronization and Vector Table
+//
+
+struct _IRQLMASK HalpIrqlMask[] = {
+ // sfw interrupt table
+ { 0 , 0 }, // 00
+ { 1 , 1 }, // 01
+ { 2 , 2 }, // 10
+ { 2 , 2 }, // 11
+ // performance counter interrupts
+ { 0 , 0 }, // 00
+ { 6 , 6 }, // 01
+ { 6 , 8 }, // 10
+ { 6 , 8 }, // 11
+ // high priority hardware interrupts
+ { 0 , 0 }, // 000000
+ { 5 , 5 }, // 000001
+ { 3 , 10 }, // 000010
+ { 5 , 5 }, // 000011
+ { 7 , 7 }, // 000100
+ { 7 , 7 }, // 000101
+ { 7 , 7 }, // 000110
+ { 7 , 7 }, // 000111
+ { 3 , 11 }, // 001000
+ { 5 , 5 }, // 001001
+ { 3 , 11 }, // 001010
+ { 5 , 5 }, // 001011
+ { 7 , 7 }, // 001100
+ { 7 , 7 }, // 001101
+ { 7 , 7 }, // 001110
+ { 7 , 7 }, // 001111
+ { 7 , 14 }, // 010000
+ { 7 , 14 }, // 010001
+ { 7 , 14 }, // 010010
+ { 7 , 14 }, // 010011
+ { 7 , 14 }, // 010100
+ { 7 , 14 }, // 010101
+ { 7 , 14 }, // 010110
+ { 7 , 14 }, // 010111
+ { 7 , 14 }, // 011000
+ { 7 , 14 }, // 011001
+ { 7 , 14 }, // 011010
+ { 7 , 14 }, // 011011
+ { 7 , 14 }, // 011100
+ { 7 , 14 }, // 011101
+ { 7 , 14 }, // 011110
+ { 7 , 14 }, // 011111
+ { 4 , 4 }, // 100000
+ { 5 , 5 }, // 100001
+ { 4 , 4 }, // 100010
+ { 5 , 5 }, // 100011
+ { 7 , 7 }, // 100100
+ { 7 , 7 }, // 100101
+ { 7 , 7 }, // 100110
+ { 7 , 7 }, // 100111
+ { 4 , 4 }, // 101000
+ { 5 , 5 }, // 101001
+ { 4 , 4 }, // 101010
+ { 5 , 5 }, // 101011
+ { 7 , 7 }, // 101100
+ { 7 , 7 }, // 101101
+ { 7 , 7 }, // 101110
+ { 7 , 7 }, // 101111
+ { 7 , 14 }, // 110000
+ { 7 , 14 }, // 110001
+ { 7 , 14 }, // 110010
+ { 7 , 14 }, // 110011
+ { 7 , 14 }, // 110100
+ { 7 , 14 }, // 110101
+ { 7 , 14 }, // 110110
+ { 7 , 14 }, // 110111
+ { 7 , 14 }, // 111000
+ { 7 , 14 }, // 111001
+ { 7 , 14 }, // 111010
+ { 7 , 14 }, // 111011
+ { 7 , 14 }, // 111100
+ { 7 , 14 }, // 111101
+ { 7 , 14 }, // 111110
+ { 7 , 14 }, // 111111
+};
diff --git a/private/ntos/nthals/hal0jens/alpha/jxisa.h b/private/ntos/nthals/hal0jens/alpha/jxisa.h
new file mode 100644
index 000000000..a59dede50
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/jxisa.h
@@ -0,0 +1,95 @@
+/*++ BUILD Version: 0001 // Increment this if a change has global effects
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1992 Digital Equipment Corporation
+
+Module Name:
+
+ jxisa.h
+
+Abstract:
+
+ This header file defines the private Hardware Architecture Layer (HAL)
+ EISA/ISA specific interfaces, defines and structures.
+
+Author:
+
+ Jeff Havens (jhavens) 20-Jun-91
+ Jeff McLeman (mcleman) 01-Jun-1992
+
+Revision History:
+
+ 17-Jul-1992 Jeff McLeman (mcleman)
+ Remove adapter object structure from here.
+
+ 01-Jun-1992 Jeff McLeman
+ modify for Jensen EISA/ISA
+
+--*/
+
+#ifndef _JXISA_
+#define _JXISA_
+
+
+//
+// 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 0x40000
+
+//
+// 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 0x20000
+
+//
+// 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 0x30000
+
+//
+// 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 16
+
+//
+// Define the maximum physical address which can be handled by an Isa card.
+//
+
+#define MAXIMUM_ISA_PHYSICAL_ADDRESS 0x01000000
+
+//
+// Define the scatter/gather flag for the Map Register Base.
+//
+
+#define NO_SCATTER_GATHER 0x00000001
+
+//
+// Define the EISA_ADAPTER flag for the Map Register Base.
+//
+
+#define EISA_ADAPTER 0x00000002
+
+//
+// Define the copy buffer flag for the index.
+//
+
+#define COPY_BUFFER 0XFFFFFFFF
+#define HOLE_BUFFER 0XFFFFFFFE
+#define SKIP_BUFFER 0XFFFFFFFD
+
+
+#endif // _JXISA_
diff --git a/private/ntos/nthals/hal0jens/alpha/jxmapio.c b/private/ntos/nthals/hal0jens/alpha/jxmapio.c
new file mode 100644
index 000000000..647fff414
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/jxmapio.c
@@ -0,0 +1,86 @@
+#if defined (JENSEN)
+
+/*++
+
+Copyright (c) 1992 Digital Equipment Corporation
+
+Module Name:
+
+ jxmapio.c
+
+Abstract:
+
+ This maps I/O addresses used by the HAL on Alpha/Jensen.
+
+Author:
+
+ Jeff McLeman (mcleman) 24-Jun-1992
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ 12-Jul-1992 Jeff McLeman (mcleman)
+ Remove RTC mapping since this is done with VTI access routines.
+
+--*/
+
+#include "halp.h"
+#include "jnsndef.h"
+
+//
+// Define global data used to locate the EISA control space.
+//
+
+PVOID HalpEisaControlBase;
+
+BOOLEAN
+HalpMapIoSpace (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine maps the HAL I/O space for an Alpha/Jensen
+ system using the Quasi VA.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ If the initialization is successfully completed, than a value of TRUE
+ is returned. Otherwise, a value of FALSE is returned.
+
+--*/
+
+{
+
+ //
+ // Map EISA control space.
+ //
+
+
+
+ HalpEisaControlBase = (PVOID)DMA_VIRTUAL_BASE;
+
+
+ //
+ // If mapped address is NULL, then return FALSE as the function
+ // value. Otherwise, return TRUE.
+ //
+
+ if (HalpEisaControlBase == NULL) {
+ return FALSE;
+
+ } else {
+ return TRUE;
+ }
+}
+
+#endif
diff --git a/private/ntos/nthals/hal0jens/alpha/jxmchk.c b/private/ntos/nthals/hal0jens/alpha/jxmchk.c
new file mode 100644
index 000000000..b13655791
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/jxmchk.c
@@ -0,0 +1,338 @@
+#if defined(JENSEN)
+
+/*++
+
+Copyright (c) 1993 Digital Equipment Corporation
+
+Module Name:
+
+ .../ntos/hal/alpha/jxinitnt.c
+
+Abstract:
+
+
+ This module implements machine check handling for JENSEN.
+
+Author:
+
+ Joe Notarangelo 11-Feb-1993
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "axp21064.h"
+
+VOID
+HalpDisplayLogout21064( PLOGOUT_FRAME_21064 LogoutFrame );
+
+
+BOOLEAN
+HalMachineCheck (
+ IN PEXCEPTION_RECORD ExceptionRecord,
+ IN PKEXCEPTION_FRAME ExceptionFrame,
+ IN PKTRAP_FRAME TrapFrame
+ )
+/*++
+
+Routine Description:
+
+ This function fields machine checks for JENSEN.
+
+Arguments:
+
+ ExceptionRecord - Supplies a pointer to the exception record for the
+ machine check. Included in the exception information
+ is the pointer to the logout frame.
+
+ ExceptionFrame - Supplies a pointer to the kernel exception frame.
+
+ TrapFrame - Supplies a pointer to the kernel trap frame.
+
+Return Value:
+
+ A value of TRUE is returned if the machine check has been
+ handled by the HAL. If it has been handled then execution may
+ resume at the faulting address. Otherwise, a value of FALSE
+ is returned.
+
+ N.B. - under some circumstances this routine may not return at
+ all.
+
+--*/
+
+{
+
+ PMCHK_STATUS MachineCheckStatus;
+
+ //
+ // JENSEN is a parity machine. If we receive a machine check it
+ // is uncorrectable. We will print the logout frame and then we
+ // will bugcheck.
+ //
+ // However, we will first check that the machine check is not
+ // marked as correctable. If the machine check is correctable it uses
+ // a differently formatted logout frame. We will ignore the frame
+ // for any machine check marked as correctable since it is an impossible
+ // condition on JENSEN.
+ //
+
+ MachineCheckStatus =
+ (PMCHK_STATUS)&ExceptionRecord->ExceptionInformation[0];
+
+ if( MachineCheckStatus->Correctable == 0 ){
+
+ HalpDisplayLogout21064(
+ (PLOGOUT_FRAME_21064)(ExceptionRecord->ExceptionInformation[1])
+ );
+
+ }
+
+ //
+ // Bugcheck to dump the rest of the machine state, this will help
+ // if the machine check is software-related.
+ //
+
+ KeBugCheckEx( DATA_BUS_ERROR,
+ (ULONG)MachineCheckStatus->Correctable,
+ (ULONG)MachineCheckStatus->Retryable,
+ 0,
+ 0 );
+
+}
+
+
+#define MAX_ERROR_STRING 100
+
+VOID
+HalpDisplayLogout21064 (
+ IN PLOGOUT_FRAME_21064 LogoutFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This function displays the logout frame for a 21064.
+
+Arguments:
+
+ LogoutFrame - Supplies a pointer to the logout frame generated
+ by the 21064.
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UCHAR OutBuffer[ MAX_ERROR_STRING ];
+
+ //
+ // Acquire ownership of the display. This is done here in case we take
+ // a machine check before the display has been taken away from the HAL.
+ // When the HAL begins displaying strings after it has lost the
+ // display ownership then the HAL will be careful not to scroll information
+ // off of the screen. This is a JENSEN feature.
+ //
+
+ HalAcquireDisplayOwnership(NULL);
+
+ //
+ // Display the machine state via the logout frame.
+ //
+
+ HalDisplayString( "\nFatal system hardware error.\n\n" );
+
+
+ sprintf( OutBuffer, "BIU_STAT : %016Lx BIU_ADDR: %016Lx\n",
+ BIUSTAT_ALL_21064( LogoutFrame->BiuStat ),
+ LogoutFrame->BiuAddr.QuadPart );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer, "FILL_ADDR: %016Lx FILL_SYN: %016Lx\n",
+ LogoutFrame->FillAddr.QuadPart,
+ FILLSYNDROME_ALL_21064(LogoutFrame->FillSyndrome) );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer, "DC_STAT : %016Lx BC_TAG : %016Lx\n",
+ DCSTAT_ALL_21064(LogoutFrame->DcStat),
+ BCTAG_ALL_21064(LogoutFrame->BcTag) );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer, "ICCSR : %016Lx ABOX_CTL: %016Lx EXC_SUM: %016Lx\n",
+ ICCSR_ALL_21064(LogoutFrame->Iccsr),
+ ABOXCTL_ALL_21064(LogoutFrame->AboxCtl),
+ EXCSUM_ALL_21064(LogoutFrame->ExcSum) );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer, "EXC_ADDR : %016Lx VA : %016Lx MM_CSR : %016Lx\n",
+ LogoutFrame->ExcAddr.QuadPart,
+ LogoutFrame->Va.QuadPart,
+ MMCSR_ALL_21064(LogoutFrame->MmCsr) );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer, "HIRR : %016Lx HIER : %016Lx PS : %016Lx\n",
+ IRR_ALL_21064(LogoutFrame->Hirr),
+ IER_ALL_21064(LogoutFrame->Hier),
+ PS_ALL_21064(LogoutFrame->Ps) );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer, "PAL_BASE : %016Lx \n",
+ LogoutFrame->PalBase.QuadPart );
+ HalDisplayString( OutBuffer );
+
+ //
+ // Print out interpretation of the error.
+ //
+
+
+ HalDisplayString( "\n" );
+
+ //
+ // Check for tag control parity error.
+ //
+
+ if( BIUSTAT_TCPERR_21064(LogoutFrame->BiuStat) == 1 ){
+
+ sprintf( OutBuffer,
+ "Tag control parity error, Tag control: P: %1x D: %1x S: %1x V: %1x\n",
+ BCTAG_TAGCTLP_21064( LogoutFrame->BcTag ),
+ BCTAG_TAGCTLD_21064( LogoutFrame->BcTag ),
+ BCTAG_TAGCTLS_21064( LogoutFrame->BcTag ),
+ BCTAG_TAGCTLV_21064( LogoutFrame->BcTag ) );
+
+ HalDisplayString( OutBuffer );
+
+ }
+
+ //
+ // Check for tag parity error.
+ //
+
+ if( BIUSTAT_TPERR_21064(LogoutFrame->BiuStat) == 1 ){
+
+ sprintf( OutBuffer,
+ "Tag parity error, Tag: 0b%17b Parity: %1x\n",
+ BCTAG_TAG_21064(LogoutFrame->BcTag),
+ BCTAG_TAGP_21064(LogoutFrame->BcTag) );
+
+ HalDisplayString( OutBuffer );
+
+ }
+
+ //
+ // Check for hard error.
+ //
+
+ if( BIUSTAT_HERR_21064(LogoutFrame->BiuStat) == 1 ){
+
+ sprintf( OutBuffer, "Hard error acknowledge: BIU CMD: %x PA: %16Lx\n",
+ BIUSTAT_CMD_21064(LogoutFrame->BiuStat),
+ LogoutFrame->BiuAddr.QuadPart );
+
+ HalDisplayString( OutBuffer );
+
+ }
+
+ //
+ // Check for soft error.
+ //
+
+ if( BIUSTAT_SERR_21064(LogoutFrame->BiuStat) == 1 ){
+
+ sprintf( OutBuffer, "Soft error acknowledge: BIU CMD: %x PA: %16Lx\n",
+ BIUSTAT_CMD_21064(LogoutFrame->BiuStat),
+ LogoutFrame->BiuAddr.QuadPart );
+
+ HalDisplayString( OutBuffer );
+
+ }
+
+
+ //
+ // Check for fill ECC errors.
+ //
+
+ if( BIUSTAT_FILLECC_21064(LogoutFrame->BiuStat) == 1 ){
+
+ sprintf( OutBuffer, "ECC error: %s\n",
+ (BIUSTAT_FILLIRD_21064(LogoutFrame->BiuStat) ?
+ "Icache Fill" : "Dcache Fill") );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer,
+ "PA: %16Lx Quadword: %x Longword0: %x Longword1: %x\n",
+ LogoutFrame->FillAddr.QuadPart,
+ BIUSTAT_FILLQW_21064(LogoutFrame->BiuStat),
+ FILLSYNDROME_LO_21064(LogoutFrame->FillSyndrome),
+ FILLSYNDROME_HI_21064(LogoutFrame->FillSyndrome) );
+
+ HalDisplayString( OutBuffer );
+
+ }
+
+ //
+ // Check for fill Parity errors.
+ //
+
+ if( BIUSTAT_FILLDPERR_21064(LogoutFrame->BiuStat) == 1 ){
+
+ sprintf( OutBuffer, "Parity error: %s\n",
+ (BIUSTAT_FILLIRD_21064(LogoutFrame->BiuStat) ?
+ "Icache Fill" : "Dcache Fill") );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer,
+ "PA: %16Lx Quadword: %x Longword0: %x Longword1: %x\n",
+ LogoutFrame->FillAddr.QuadPart,
+ BIUSTAT_FILLQW_21064(LogoutFrame->BiuStat),
+ FILLSYNDROME_LO_21064(LogoutFrame->FillSyndrome),
+ FILLSYNDROME_HI_21064(LogoutFrame->FillSyndrome) );
+
+ HalDisplayString( OutBuffer );
+
+ }
+
+ //
+ // Check for multiple hard errors.
+ //
+
+ if( BIUSTAT_FATAL1_21064(LogoutFrame->BiuStat) == 1 ){
+
+ HalDisplayString( "Multiple external/tag errors detected.\n" );
+
+ }
+
+ //
+ // Check for multiple fill errors.
+ //
+
+ if( BIUSTAT_FATAL2_21064(LogoutFrame->BiuStat) == 1 ){
+
+ HalDisplayString( "Multiple fill errors detected.\n" );
+
+ }
+
+
+ //
+ // return to caller
+ //
+
+ return;
+}
+
+#endif //JENSEN
diff --git a/private/ntos/nthals/hal0jens/alpha/jxport.c b/private/ntos/nthals/hal0jens/alpha/jxport.c
new file mode 100644
index 000000000..df9fcf4ad
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/jxport.c
@@ -0,0 +1,604 @@
+#if defined(JENSEN)
+
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1992 Digital Equipment Corporation
+
+Module Name:
+
+ jxport.c
+
+Abstract:
+
+ This module implements the code that provides communication between
+ the kernel debugger on a Jensen system and the host system.
+
+ Stolen from ../mips/jxport.c
+
+Author:
+
+ Miche Baker-Harvey (miche) 01-June-1992
+ Jeff McLeman [DEC] 02-Feb-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Joe Notarangelo 21-Jun-1992
+ update to use super-page access to serial port so we aren't depend
+ on translation code, this will allow us to debug the translation
+ code, use serial line 2
+
+
+--*/
+
+
+#include "halp.h"
+#include "jxserp.h"
+
+
+//
+// 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.
+//
+PSP_READ_REGISTERS SP_READ;
+PSP_WRITE_REGISTERS SP_WRITE;
+
+//
+// Define forward referenced prototypes.
+//
+
+SP_LINE_STATUS
+KdReadLsr (
+ IN BOOLEAN WaitReason
+ );
+
+//
+// Define baud rate divisor to be used on the debugger port.
+//
+
+UCHAR HalpBaudRateDivisor = 0;
+
+
+ULONG
+HalpGetByte (
+ IN PUCHAR Input,
+ IN BOOLEAN Wait
+ )
+
+/*++
+
+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 error encountered during reading.
+ CP_GET_NODATA is returned if timeout.
+
+--*/
+{
+ 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 = inVti(&SP_READ->ReceiveBuffer);
+
+ //
+ // If using modem controls, then skip any incoming data while
+ // ReceiveData not set.
+ //
+
+ if (KdUseModemControl) {
+ DataByte = inVti(&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:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PCONFIGURATION_COMPONENT_DATA ConfigurationEntry;
+ UCHAR DataByte;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
+ PCM_SERIAL_DEVICE_DATA DeviceData;
+ ULONG KdPortEntry;
+ PCM_PARTIAL_RESOURCE_LIST List;
+ ULONG MatchKey;
+ ULONG BaudRate;
+ ULONG BaudClock;
+ ULONG Remainder;
+
+ //
+ // 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 rate divisor to
+ // six, which is 19.2Kbps on Jensen. Otherwise, set the baud rate divisor
+ // to the correct value for 19.2 baud communication.
+ //
+
+ BaudClock = 1843200;
+ 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;
+ }
+ }
+
+ HalpBaudRateDivisor = (UCHAR)(BaudClock / (BaudRate*16));
+
+ //
+ // round up
+ //
+ Remainder = BaudClock % (BaudRate*16);
+ if ((Remainder*2) > BaudClock) {
+ HalpBaudRateDivisor++;
+ }
+
+ //
+ // If the debugger is not being enabled, then return.
+ //
+
+ if (Initialize == FALSE) {
+ return TRUE;
+ }
+
+ //
+ // Establish pointers to serial line register structures
+ // Note: the natural port number addresses are used
+ //
+
+ if ( DebugParameters->CommunicationPort == 1 ) {
+ SP_READ = ((PSP_READ_REGISTERS)(COMA_PORT_BASE));
+ SP_WRITE = ((PSP_WRITE_REGISTERS)(COMA_PORT_BASE));
+ KdComPortInUse = (PUCHAR)0x3f8;
+ } else {
+ SP_READ = ((PSP_READ_REGISTERS)(COMB_PORT_BASE));
+ SP_WRITE = ((PSP_WRITE_REGISTERS)(COMB_PORT_BASE));
+ KdComPortInUse = (PUCHAR)0x2f8;
+ }
+
+ //
+ // Clear the divisor latch, clear all interrupt enables, and reset and
+ // disable the FIFO's.
+ //
+
+ outVti( &SP_WRITE->LineControl, 0x0 );
+ outVti( &SP_WRITE->InterruptEnable, 0x0 );
+
+
+ // We shouldn't have to do anything with the FIFO here -
+
+ //
+ // Set the divisor latch and set the baud rate to 19200 baud.
+ //
+ // Note: the references to TransmitBuffer and InterruptEnable are
+ // actually the Divisor Latch LSB and MSB registers respectively
+ DataByte = 0;
+ ((PSP_LINE_CONTROL)(&DataByte))->DivisorLatch = 1;
+ outVti(&SP_WRITE->LineControl, DataByte);
+ outVti(&SP_WRITE->TransmitBuffer, HalpBaudRateDivisor);
+ outVti(&SP_WRITE->InterruptEnable, 0x0);
+
+ //
+ // 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;
+ outVti(&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;
+ outVti(&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 = inVti(&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 = inVti(&SP_READ->ModemStatus);
+// } while (((PSP_MODEM_STATUS)(&LsrByte))->DataSetReady == 0);
+
+ //
+ // Transmit data.
+ //
+
+ outVti(&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 receive or a transmit.
+ //
+
+ DataLsr = inVti(&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 = inVti(&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);
+}
+
+#endif // JENSEN
diff --git a/private/ntos/nthals/hal0jens/alpha/jxprof.h b/private/ntos/nthals/hal0jens/alpha/jxprof.h
new file mode 100644
index 000000000..73869b657
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/jxprof.h
@@ -0,0 +1,77 @@
+/*++
+
+Copyright (c) 1992 Digital Equipment Corporation
+
+Module Name:
+
+ jxprof.h
+
+Abstract:
+
+ This header file defines profile counter hardware in the
+ 82357 PIC chip used on the Alpha/Jensen Platform.
+
+Author:
+
+ Jeff McLeman (mcleman) 5-June-1992
+
+Revision History:
+
+--*/
+
+#ifndef _JXPROF_
+#define _JXPROF_
+
+
+//
+// Define the timer values for the Profiler
+//
+
+#define PIC_BINARY 0
+#define PIC_BCD 1
+
+#define PIC_MODE0 0x00 // xxxx000x
+#define PIC_MODE1 0x02 // xxxx001x
+#define PIC_MODE2 0x04 // xxxx010x
+#define PIC_MODE3 0x06 // xxxx011x
+#define PIC_MODE4 0x08 // xxxx100x
+#define PIC_MODE5 0x0A // xxxx101x
+
+#define PIC_CLC 0x00 // xx00xxxx
+#define PIC_RWLSBO 0x10 // xx01xxxx
+#define PIC_RWMSBO 0x20 // xx10xxxx
+#define PIC_RWLSBMSB 0x30 // xx11xxxx
+
+#define PIC_SC0 0x00 // 00xxxxxx
+#define PIC_SC1 0x40 // 01xxxxxx
+#define PIC_SC2 0x80 // 10xxxxxx
+#define PIC_RBC 0xC0 // 11xxxxxx
+
+
+#define PIC_SCALE_FACTOR 10 * 1000 // # of microsecond units times 10.
+
+//
+// Define a macro to set and enable the system profiler timer.
+// Note that the interval 'c' is in 100nS units.
+// Note that also the interval is incremented AFTER it is scaled.
+// This is due to the fact that the timer counts down to 1 in mode 2
+//
+
+#define PIC_PROFILER_ON(c)\
+ WRITE_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->CommandMode1,\
+ (ULONG)(PIC_BINARY | PIC_MODE2 | PIC_RWLSBMSB | PIC_SC0));\
+ WRITE_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->Timer1,\
+ (ULONG)((c) & 0xff) );\
+ WRITE_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->Timer1,\
+ (ULONG)(((c)>> 8) & 0xff) )
+
+//
+// Define a macro to shut down the profiler
+//
+
+#define PIC_PROFILER_OFF()\
+ WRITE_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->CommandMode1,\
+ (ULONG)(PIC_BINARY | PIC_MODE4 | PIC_RWLSBMSB | PIC_SC0))
+
+
+#endif // _JXPROF_
diff --git a/private/ntos/nthals/hal0jens/alpha/jxprom.c b/private/ntos/nthals/hal0jens/alpha/jxprom.c
new file mode 100644
index 000000000..bd3eaa4d9
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/jxprom.c
@@ -0,0 +1,1098 @@
+/*++
+
+Copyright (c) 1993 Digital Equipment Corporation
+
+Module Name:
+
+ jxprom.c
+
+Abstract:
+
+ This module provides support for different kinds of ROMs/PROMs/Flash
+ ROMs in Alpha AXP machines.
+
+ This file, and rom.c, make no attempt at universal ROM-support.
+
+ Current support set:
+
+ Intel: 28F008SA 1 megabyte Flash Memory
+
+ AMD: Am29F010 128KB Sector Erase Flash Memory
+
+
+Author:
+
+ John DeRosa 4-May-1993
+
+Revision History:
+
+ Jeff McLeman 13-May-1993
+ Adapted for HAL use from Firmware module.
+
+--*/
+
+#include "halp.h"
+#include "jxenv.h"
+#include "jxprom.h"
+#include "arccodes.h"
+
+//
+// Function prototypes
+//
+
+ARC_STATUS
+HalpErase28F008SA(
+ IN PUCHAR EraseAddress
+ );
+
+
+ARC_STATUS
+HalpByteWrite28F008SA(
+ IN PUCHAR WriteAddress,
+ IN UCHAR WriteData
+ );
+
+ARC_STATUS
+HalpEraseAM29F010 (
+ IN PUCHAR EraseAddress
+ );
+
+ARC_STATUS
+HalpByteWriteAM29F010 (
+ IN PUCHAR WriteAddress,
+ IN UCHAR WriteData
+ );
+
+//
+// ROM identification and control valueds.
+//
+// These are based on:
+//
+// Am29F010: AMD publication #16736, Rev. C, Amendment/0, September 1992.
+// 28F008SA: Intel order number 290429-003, September 1992.
+//
+// Table notes:
+//
+// Addresses for the ID command and response sequences are absolute,
+// since this code assumes homogeneous ROM arrays. The code will only
+// test the chip at the lowest Jensen ROM address.
+//
+// Offsets for the Reset and Set Read-mode commands are relative to the
+// base address of the individual ROM chip.
+//
+// Addresses passed to the erase-block function are within the block
+// to be erased.
+//
+// Addresses passed to the write-byte function are the address of the byte
+// to be written.
+//
+// The chip block size must be less than or equal to 64KB.
+//
+// N.B. The function that determines the ROM type will test each entry
+// in RomValues, starting at the beginning. This involves issuing write
+// commands to the ROM chip. So care must be taken that the ID command
+// write sequence for ROM type "n" will not have a deliterious effect on
+// other ROM types which may be in the machine, but are not identified until
+// RomValues entry "n + x".
+//
+//
+
+ROM_VALUES RomValues[InvalidROM] = {
+
+ { 16, // Standard stall amount
+ 1, // ID command length
+ 2, // ID response length
+ 1, // Reset command length
+ 1, // Read command length
+ I28F008SA, // ROM being described
+ 0x100000, // 1MB per chip
+ 0x10000, // 64KB per block
+ { {(PUCHAR)PROM_VIRTUAL_BASE, 0x90} }, // ID command sequence
+ { {(PUCHAR)PROM_VIRTUAL_BASE, 0x89}, // ID response sequence
+ {(PUCHAR)PROM_VIRTUAL_BASE+1, 0xa2} },
+ { {0, 0x50} }, // Reset command sequence
+ { {0, 0xff} }, // Read command sequence
+ HalpErase28F008SA, // Sector erase function
+ HalpByteWrite28F008SA // Byte write function
+ },
+
+ { 14, // Standard stall amount
+ 3, // ID command length
+ 2, // ID response length
+ 3, // Reset command length
+ 3, // Read command length
+ Am29F010, // ROM being described
+ 0x20000, // 128KB per chip
+ 0x4000, // 16KB per block
+ { {(PUCHAR)PROM_VIRTUAL_BASE+0x5555, 0xaa},
+ {(PUCHAR)PROM_VIRTUAL_BASE+0x2aaa, 0x55},
+ {(PUCHAR)PROM_VIRTUAL_BASE+0x5555, 0x90} }, // ID command sequence
+ { {(PUCHAR)PROM_VIRTUAL_BASE, 1}, // ID response sequence
+ {(PUCHAR)PROM_VIRTUAL_BASE+1, 0x20} },
+ { {0x5555, 0xaa},
+ {0x2aaa, 0x55},
+ {0x5555, 0xf0} }, // Reset command sequence
+ { {0x5555, 0xaa},
+ {0x2aaa, 0x55},
+ {0x5555, 0xf0} }, // Read command sequence
+ HalpEraseAM29F010, // Sector erase function
+ HalpByteWriteAM29F010 // Byte write function
+ }
+};
+
+
+//
+// Miscellaneous notes.
+//
+// A call must first be made to HalpROMDetermineMachineROMType. If this
+// returns ESUCCESS, then it has loaded the ROM type into the global variable
+// MachineROMType.
+//
+// After MachineROMType has been loaded, these functions may be called
+// to manipulate the system ROM:
+//
+// HalpROMByteWrite
+// HalpROMErase64KB
+// HalpROMEraseBlock
+// HalpROMResetStatus
+// HalpROMSetARCDataToReadMode
+// HalpROMSetReadMode
+//
+// HalpROMErase64KB and HalpROMSetARCDataToReadMode work on a "virtual"
+// 64KB ROM block, for compatibility with the first version of Jensen
+// hardware.
+//
+//
+// The type of ROM in this machine.
+//
+
+ROM_TYPE MachineROMType = 0;
+
+
+ARC_STATUS
+Check28F008SAStatusAndClear (
+ IN ULONG WhichToCheck
+ )
+/*++
+
+Routine Description:
+
+ This checks the status of an Intel 28F008SA 1MB Flash ROM. The
+ base address of the Jensen space, PROM_VIRTUAL_BASE, is used since
+ we know there is only one of these chips in the machine.
+
+ Hack: The hardwired values here should be changed to come out of
+ the RomValues array.
+
+Arguments:
+
+ WhichToCheck = 0 if a block-erase status check is desired.
+ = 1 if a byte-write status check is desired.
+
+ROM state on exit:
+
+ The status register is cleared.
+
+Return Value:
+
+ Returns ESUCCESS if the status is OK.
+ Otherwise, EIO is returned.
+
+--*/
+
+{
+ UCHAR FooBar;
+
+ //
+ // Check the full status when the PROM's write state machine is ready.
+ //
+
+ while (((FooBar = READ_PORT_UCHAR((PUCHAR)PROM_VIRTUAL_BASE)) &
+ 0x80) == 0 ) {
+ KeStallExecutionProcessor(10);
+ }
+
+ KeStallExecutionProcessor(10);
+ HalpROMResetStatus((PUCHAR)PROM_VIRTUAL_BASE);
+
+ switch (WhichToCheck) {
+
+ //
+ // block-erase status check
+ //
+
+ case 0:
+
+ if ( ((FooBar & 0x28) != 0) || ((FooBar & 0x30) == 0x30) ) {
+ // Error in erase
+ return EIO;
+ } else {
+ // Erase was successful
+ return ESUCCESS;
+ }
+
+ //
+ // byte-write status check
+ //
+
+ case 1:
+
+ if (FooBar & 0x18) {
+ // Error in write
+ return EIO;
+ } else {
+ // Write was successful
+ return ESUCCESS;
+ }
+
+
+ //
+ // We should never get here.
+ //
+
+ default:
+ return EIO;
+ }
+}
+
+
+ARC_STATUS
+HalpErase28F008SA(
+ IN PUCHAR EraseAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This erases a block in an Intel 28F008SA 1MB Flash ROM. The
+ base address of the Jensen space, PROM_VIRTUAL_BASE, is used since
+ we know there is only one of these chips in the machine.
+
+ Hack: The hardwired values here should be changed to come out of
+ the RomValues array.
+
+Arguments:
+
+ EraseAddress - An address within the block to be erased.
+
+ROM state on exit:
+
+ The status register is left in a cleared (reset) state.
+ The ROM is left in read-array mode.
+
+Return Value:
+
+ Returns ESUCCESS if the erase was successful.
+ Otherwise, EIO is returned.
+
+--*/
+
+{
+ ULONG FooBar;
+ KIRQL OldIrql;
+
+ for (FooBar = 0; FooBar <= 10; FooBar++) {
+
+ HalpROMResetStatus((PUCHAR)PROM_VIRTUAL_BASE);
+
+ KeRaiseIrql(DEVICE_LEVEL, &OldIrql);
+
+ WRITE_PORT_UCHAR (EraseAddress, 0x20);
+ HalpMb();
+ WRITE_PORT_UCHAR (EraseAddress, 0xd0);
+ HalpMb();
+
+ KeLowerIrql(OldIrql);
+
+ // Stall 1 seconds
+ HalpPromDelay(3000);
+
+ if (Check28F008SAStatusAndClear(0) == ESUCCESS) {
+ HalpROMSetReadMode((PUCHAR)PROM_VIRTUAL_BASE);
+ return ESUCCESS;
+ }
+
+ // In case the device is busy, give it some time to settle.
+ HalpPromDelay(6000);
+ }
+
+
+ //
+ // If we get here, we have tried unsuccessfully 10 times to erase
+ // this block. Return an error.
+ //
+
+ HalpROMSetReadMode((PUCHAR)PROM_VIRTUAL_BASE);
+ return EIO;
+}
+
+
+ARC_STATUS
+HalpByteWrite28F008SA(
+ IN PUCHAR WriteAddress,
+ IN UCHAR WriteData
+ )
+
+/*++
+
+Routine Description:
+
+ This writes a byte in the Alpha/Jensen 1MB PROM. It retries up to
+ 20 times if the write status register indicates failure, or a read
+ of the location indicates that the write was partially done
+ by the device.
+
+ Hack: The hardwired values here should be changed to come out of
+ the RomValues array.
+
+Arguments:
+
+ WriteAddress = meta-virtual address of the byte to be written.
+ WriteData = byte to be written.
+
+ROM state on exit:
+
+ The byte is written, and the WSM status register is modified.
+
+Return Value:
+
+ ESUCCESS if the write was successful.
+ Otherwise, EIO.
+
+--*/
+
+{
+ ULONG Index;
+ UCHAR WSMStatus;
+ KIRQL OldIrql;
+
+ HalpROMResetStatus((PUCHAR)PROM_VIRTUAL_BASE);
+
+ for (Index = 0; Index < 20; Index++) {
+
+ KeRaiseIrql(DEVICE_LEVEL, &OldIrql);
+
+ WRITE_PORT_UCHAR (WriteAddress, 0x40);
+ HalpMb();
+ WRITE_PORT_UCHAR (WriteAddress, WriteData);
+ HalpMb();
+
+ KeLowerIrql(OldIrql);
+
+ //
+ // The device should need only 14 microseconds.
+ //
+
+ KeStallExecutionProcessor(14);
+
+ if (Check28F008SAStatusAndClear(1) != ESUCCESS) {
+
+ //
+ // The write failed. Ensure status is clear and see if we
+ // can retry.
+ //
+
+ HalpROMResetStatus((PUCHAR)PROM_VIRTUAL_BASE);
+ HalpROMSetReadMode((PUCHAR)PROM_VIRTUAL_BASE);
+ DbgPrint("? Write failed to address %x. Wrote %x, ",
+ WriteAddress, WriteData);
+ DbgPrint("verify returns %x.\r\n",
+ READ_PORT_UCHAR((PUCHAR)WriteAddress));
+
+ if (READ_PORT_UCHAR(WriteAddress) != 0xff) {
+ DbgPrint("RETRY ABORTED!\r\n");
+ return EIO;
+ } else {
+ DbgPrint("Retrying..\r\n");
+ }
+
+ } else {
+
+ //
+ // The write succeeded.
+ //
+
+ return ESUCCESS;
+ }
+
+ }
+
+
+ //
+ // We failed to write the byte after 20 tries.
+ //
+
+ return EIO;
+
+}
+
+
+ARC_STATUS
+CheckAM29F010Status (
+ IN BOOLEAN SectorErase,
+ IN PUCHAR Address,
+ IN UCHAR Data
+ )
+/*++
+
+Routine Description:
+
+ This checks the status of an AMD 29F010 128KB ROM chip after a
+ byte write or sector erase command has been issued. Data Polling
+ is used.
+
+Arguments:
+
+ SectorErase - TRUE if a sector erase is under way.
+ FALSE if a byte write is under way.
+
+ Address - The address of the ROM byte that was just
+ written, or an address within the chip that
+ was just given an erase command.
+
+ Data - If a byte write is under way, this is the byte
+ that was written.
+
+ If a sector erase is under way, this must be
+ a value in the range 0xf0 -- 0xff.
+
+ROM state on exit:
+
+ The ROM is left at the end of its sector erase or byte write algorithm.
+
+Return Value:
+
+ Returns ESUCCESS if the status is OK.
+
+ Otherwise, EIO is returned.
+
+--*/
+
+{
+ UCHAR Character;
+ ULONG Retries;
+
+ //
+ // If we are doing an erase command, check whether the erase command
+ // was accepted. This is supposed to happen within the first 100 usec.
+ //
+
+ if (SectorErase) {
+
+ Retries = 0;
+
+ while ((READ_PORT_UCHAR(Address) & 0x08) != 0x08) {
+ Retries++;
+ KeStallExecutionProcessor(20);
+ if (Retries == 10) {
+ return (EIO);
+ }
+ }
+ }
+
+ //
+ // Do data polling until the device signals success or a timeout.
+ //
+
+ while (TRUE) {
+
+ Character = READ_PORT_UCHAR(Address);
+
+ //
+ // Has the device finished?
+ //
+
+ if (((Character ^ Data) & 0x80) == 0) {
+
+ //
+ // DQ7 says yes!
+ //
+
+ return (ESUCCESS);
+ }
+
+ //
+ // Check for time-out. If a possible time-out condition, DQ7 is
+ // re-read and re-checked to account for the case of simultaneous
+ // updates to DQ5 and DQ7.
+ //
+
+ if (Character & 0x20) {
+
+ if (((READ_PORT_UCHAR(Address) ^ Data) & 0x80) == 0) {
+
+ // DQ7 says success!
+ return (ESUCCESS);
+
+ } else {
+
+ // DQ5 and DQ7 say time-out.
+ return (EIO);
+ }
+ }
+ }
+}
+
+ARC_STATUS
+HalpEraseAM29F010 (
+ IN PUCHAR EraseAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This erases a block in an AMD AM29F010 128KB Flash ROM.
+
+Arguments:
+
+ EraseAddress - An address within the block to be erased.
+
+ROM state on exit:
+
+ The status register is left in a cleared (reset) state.
+ The ROM is left in read-array mode.
+
+Return Value:
+
+ Returns ESUCCESS if the erase was successful.
+ Otherwise, EIO is returned.
+
+--*/
+
+{
+ ULONG FooBar;
+ PUCHAR Address;
+ KIRQL OldIrql;
+
+ //
+ // Concoct the base address of this ROM chip.
+ //
+
+ Address = (PUCHAR)
+ ((ULONG)EraseAddress &
+ ~(RomValues[MachineROMType].BytesPerChip - 1));
+
+ for (FooBar = 0; FooBar <= 10; FooBar++) {
+
+ HalpROMResetStatus(EraseAddress);
+
+ KeRaiseIrql(DEVICE_LEVEL, &OldIrql);
+
+ WRITE_PORT_UCHAR (Address+0x5555, 0xaa);
+ KeStallExecutionProcessor(2);
+ WRITE_PORT_UCHAR (Address+0x2aaa, 0x55);
+ KeStallExecutionProcessor(2);
+ WRITE_PORT_UCHAR (Address+0x5555, 0x80);
+ KeStallExecutionProcessor(2);
+ WRITE_PORT_UCHAR (Address+0x5555, 0xaa);
+ KeStallExecutionProcessor(2);
+ WRITE_PORT_UCHAR (Address+0x2aaa, 0x55);
+ KeStallExecutionProcessor(2);
+ WRITE_PORT_UCHAR (EraseAddress, 0x30);
+
+ KeLowerIrql(OldIrql);
+
+ if (CheckAM29F010Status(TRUE, EraseAddress, 0xff) == ESUCCESS) {
+ HalpROMSetReadMode(EraseAddress);
+ return ESUCCESS;
+ }
+
+ //
+ // We have to retry the erase. Give the device some time to settle.
+ //
+
+ HalpPromDelay(3000);
+ }
+
+
+ //
+ // If we get here, we have tried unsuccessfully 10 times to erase
+ // this block. Return an error.
+ //
+
+ HalpROMSetReadMode(EraseAddress);
+
+ return EIO;
+}
+
+ARC_STATUS
+HalpByteWriteAM29F010 (
+ IN PUCHAR WriteAddress,
+ IN UCHAR WriteData
+ )
+
+/*++
+
+Routine Description:
+
+ This writes a byte in an AMD AM29F010 128KB Flash ROM. It retries up to
+ 20 times if the write status register indicates failure, or a read
+ of the location indicates that the write was partially done
+ by the device.
+
+Arguments:
+
+ WriteAddress = meta-virtual address of the byte to be written.
+ WriteData = byte to be written.
+
+ROM state on exit:
+
+ The byte is written, and the WSM status register is modified.
+
+Return Value:
+
+ ESUCCESS if the write was successful.
+ Otherwise, EIO.
+
+--*/
+
+{
+ ULONG Index;
+ UCHAR WSMStatus;
+ PUCHAR Address;
+ KIRQL OldIrql;
+
+
+ //
+ // Concoct the base address of this ROM chip.
+ //
+
+ Address = (PUCHAR)
+ ((ULONG)WriteAddress &
+ ~(RomValues[MachineROMType].BytesPerChip - 1));
+
+ HalpROMResetStatus(WriteAddress);
+
+ for (Index = 0; Index < 20; Index++) {
+
+ KeRaiseIrql(DEVICE_LEVEL, &OldIrql);
+
+ WRITE_PORT_UCHAR (Address+0x5555, 0xaa);
+ KeStallExecutionProcessor(2);
+ WRITE_PORT_UCHAR (Address+0x2aaa, 0x55);
+ KeStallExecutionProcessor(2);
+ WRITE_PORT_UCHAR (Address+0x5555, 0xa0);
+ KeStallExecutionProcessor(2);
+ WRITE_PORT_UCHAR (WriteAddress, WriteData);
+ KeStallExecutionProcessor(2);
+
+ KeLowerIrql(OldIrql);
+
+ if (CheckAM29F010Status(FALSE, WriteAddress, WriteData) != ESUCCESS) {
+
+ //
+ // The write failed. Ensure status is clear and see if we
+ // can retry.
+ //
+
+ HalpROMResetStatus(WriteAddress);
+ HalpROMSetReadMode(WriteAddress);
+ DbgPrint("? Write failed to address %x. Wrote %x, ",
+ WriteAddress, WriteData);
+ DbgPrint("verify returns %x.\r\n",
+ READ_PORT_UCHAR((PUCHAR)WriteAddress));
+
+ if (READ_PORT_UCHAR(WriteAddress) != 0xff) {
+ DbgPrint("RETRY ABORTED!\r\n");
+ return EIO;
+ } else {
+ DbgPrint("Retrying..\r\n");
+ }
+
+ } else {
+
+ //
+ // The write succeeded.
+ //
+
+ return ESUCCESS;
+ }
+
+ }
+
+
+ //
+ // We failed to write the byte after 20 tries.
+ //
+
+ return EIO;
+}
+
+
+ARC_STATUS
+HalpROMDetermineMachineROMType (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This determines what kind of Flash ROM is in the machine.
+
+ The ROMs making up the Flash ROM space are assumed to be
+ homogeneous. So, we only check one chip.
+
+ N.B. The RomValues array must be tested in ascending order,
+
+ N.B. This function must not call any of the HalpROM... functions!
+
+Arguments:
+
+ ROMType - A pointer to a variable that will receive the type
+ of ROM in the machine, if the return value is ESUCCESS.
+
+ROM state on exit:
+
+ Left in read-array mode.
+
+Return Value:
+
+ ESUCCESS if we could successfully identify the ROM.
+ Otherwise, and error condition.
+
+--*/
+
+{
+ BOOLEAN Match;
+ ROM_TYPE Index;
+ ULONG IDIndex;
+
+ //
+ // Loop through each ROM type, trying the ID Command Sequence for
+ // each.
+ //
+
+ for (Index = 0; Index < InvalidROM; Index++) {
+
+ //
+ // Send the command.
+ //
+
+ for (IDIndex = 0;
+ IDIndex < RomValues[Index].IdCommandLength;
+ IDIndex++) {
+
+ WRITE_PORT_UCHAR(RomValues[Index].IdCommand[IDIndex].Address,
+ RomValues[Index].IdCommand[IDIndex].Value);
+
+ KeStallExecutionProcessor(RomValues[MachineROMType].StallAmount);
+ }
+
+ //
+ // Check the response.
+ //
+
+ Match = TRUE;
+
+ for (IDIndex = 0;
+ IDIndex < RomValues[Index].IdResponseLength;
+ IDIndex++) {
+
+ if (RomValues[Index].IdResponse[IDIndex].Value !=
+ READ_PORT_UCHAR(RomValues[Index].IdResponse[IDIndex].Address)) {
+ //
+ // This portion of the Response sequence did not match.
+ //
+
+ Match = FALSE;
+ break;
+ }
+ }
+
+ if (Match == FALSE) {
+ continue;
+ }
+
+ //
+ // We have found a match. Set the ROM to read-array mode, and then
+ // return the current entry as the ROM type.
+ //
+
+ MachineROMType = RomValues[Index].ROMType;
+ HalpROMResetStatus((PUCHAR)PROM_VIRTUAL_BASE);
+ HalpROMSetReadMode((PUCHAR)PROM_VIRTUAL_BASE);
+ return (ESUCCESS);
+ }
+
+ //
+ // We have not found a match. Return an error.
+ //
+
+ return (EIO);
+}
+
+VOID
+HalpROMResetStatus(
+ IN PUCHAR Address
+ )
+/*++
+
+Routine Description:
+
+ This clears the status register in a ROM chip.
+
+Arguments:
+
+ Address - An address within the chip that is to be reset.
+
+ROM state on exit:
+
+ The status register is left in a cleared (reset) state.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Index;
+ KIRQL OldIrql;
+
+ //
+ // Concoct the base address of this ROM chip.
+ //
+ // Remember, C is call by value!
+ //
+
+ Address = (PUCHAR)
+ ((ULONG)Address & ~(RomValues[MachineROMType].BytesPerChip - 1));
+
+ for (Index = 0;
+ Index < RomValues[MachineROMType].ResetCommandLength;
+ Index++) {
+ KeRaiseIrql(DEVICE_LEVEL, &OldIrql);
+ WRITE_PORT_UCHAR (Address +
+ RomValues[MachineROMType].ResetCommand[Index].Offset,
+ RomValues[MachineROMType].ResetCommand[Index].Value);
+ HalpMb();
+ KeLowerIrql(OldIrql);
+
+ KeStallExecutionProcessor(RomValues[MachineROMType].StallAmount);
+ }
+}
+
+VOID
+HalpROMSetReadMode(
+ IN PUCHAR Address
+ )
+/*++
+
+Routine Description:
+
+ This returns a ROM chip to read-array mode.
+
+Arguments:
+
+ Address - An address within the chip that is to be set to
+ read-array mode.
+
+ROM state on exit:
+
+ The chip is left in read-array mode.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Index;
+ KIRQL OldIrql;
+
+ //
+ // Concoct the base address of this ROM chip.
+ //
+ // Remember, C is call by value!
+ //
+
+ Address = (PUCHAR)
+ ((ULONG)Address & ~(RomValues[MachineROMType].BytesPerChip - 1));
+
+ for (Index = 0;
+ Index < RomValues[MachineROMType].ReadCommandLength;
+ Index++) {
+ KeRaiseIrql(DEVICE_LEVEL, &OldIrql);
+ WRITE_PORT_UCHAR (Address +
+ RomValues[MachineROMType].ReadCommand[Index].Offset,
+ RomValues[MachineROMType].ReadCommand[Index].Value);
+ HalpMb();
+ KeLowerIrql(OldIrql);
+
+ KeStallExecutionProcessor(RomValues[MachineROMType].StallAmount);
+ }
+}
+
+VOID
+HalpROMSetARCDataToReadMode (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the virtual 64KB ROM block that houses the
+ CDS tree, environment variables, and EISA configuration data to
+ read-array mode. For devices with a block size smaller than
+ 64KB, we issues set read-mode commands to every block within this
+ virtual 64KB block. This is overkill, but it is easy.
+
+Arguments:
+
+ None.
+
+ROM state on exit:
+
+ Set to read-array mode.
+
+Return Value:
+
+ None
+
+--*/
+{
+ PUCHAR Address;
+ ULONG Index;
+
+ Address = (PUCHAR)NVRAM_CONFIGURATION;
+
+ //
+ // Hackhack: At some point change this to eliminate the division.
+ //
+
+ for (Index = 0;
+ Index < (SIXTY_FOUR_KB / RomValues[MachineROMType].BytesPerBlock);
+ Index++) {
+ HalpROMSetReadMode(Address);
+ Address += RomValues[MachineROMType].BytesPerBlock;
+ }
+}
+
+ARC_STATUS
+HalpROMByteWrite(
+ IN PUCHAR WriteAddress,
+ IN UCHAR WriteData
+ )
+
+/*++
+
+Routine Description:
+
+ This writes a byte in the Alpha/Jensen ROM space.
+
+Arguments:
+
+ WriteAddress = meta-virtual address of the byte to be written.
+ WriteData = byte to be written.
+
+ROM state on exit:
+
+ The byte is written, and the WSM status register is modified.
+
+Return Value:
+
+ Whatever is returned from the ROM-specific write function.
+
+--*/
+
+{
+ return ((*RomValues[MachineROMType].ByteWrite)(WriteAddress, WriteData));
+}
+
+ARC_STATUS
+HalpROMEraseBlock(
+ IN PUCHAR EraseAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This erases a single block in the Alpha/Jensen ROM space. The number
+ of bytes erased is dependent on the underlying chip being manipulated.
+
+Arguments:
+
+ EraseAddress - An address within the block to be erased.
+
+ROM state on exit:
+
+ On a successful return, the status register is left in a reset state and
+ the ROM is in read-array mode.
+
+Return Value:
+
+ Whatever is returned from the ROM-specific erase function.
+
+--*/
+
+{
+ return ((*RomValues[MachineROMType].SectorErase)(EraseAddress));
+}
+
+ARC_STATUS
+HalpROMErase64KB(
+ IN PUCHAR EraseAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This erases a 64KB logical block in the Alpha/Jensen ROM space.
+
+ To minimize code changes with the previous version of the firmware,
+ the PROM space is treated as though it has a block size of 64KB, even
+ if the block size is must less than that.
+
+Arguments:
+
+ EraseAddress - An address within the block to be erased.
+
+ROM state on exit:
+
+ On a successful return, the status register is left in a reset state and
+ the ROM is in read-array mode.
+
+Return Value:
+
+ Returns ESUCCESS if the erase was successful.
+ Otherwise, EIO is returned.
+
+--*/
+
+{
+ ARC_STATUS Status;
+ ULONG Index;
+
+ //
+ // Create the base address of the 64KB block to be cleared.
+ //
+ // Remember, C is call by value!
+ //
+
+ EraseAddress = (PUCHAR)((ULONG)EraseAddress & ~(SIXTY_FOUR_KB - 1));
+
+ //
+ // Now erase as many blocks as is necessary to erase a 64KB virtual block.
+ //
+ // Hack: I should eliminate the integer division.
+ //
+
+ for (Index = 0;
+ Index < (SIXTY_FOUR_KB / RomValues[MachineROMType].BytesPerBlock);
+ Index++) {
+
+ if ((Status = (*RomValues[MachineROMType].SectorErase)(EraseAddress))
+ != ESUCCESS) {
+ break;
+ }
+
+ EraseAddress += RomValues[MachineROMType].BytesPerBlock;
+ }
+
+ return (Status);
+}
diff --git a/private/ntos/nthals/hal0jens/alpha/jxprom.h b/private/ntos/nthals/hal0jens/alpha/jxprom.h
new file mode 100644
index 000000000..66c0aa09e
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/jxprom.h
@@ -0,0 +1,218 @@
+/*++
+
+Copyright (c) 1993 Digital Equipment Corporation
+
+Module Name:
+
+ jxprom.h
+
+Abstract:
+
+ This module defines structures and datatypes for use in reading
+ and writing ROMs/PROMs/Flash ROMs.
+
+ This file, and rom.c, makes no attempt at universal ROM-support.
+
+Author:
+
+ John DeRosa 4-May-1993
+
+Revision History:
+
+ Jeff McLeman 13-May-1993
+
+ Adapted for use in Hal
+
+--*/
+
+//
+// All ROM manipulations (reading, writing, etc.) are done through
+// an array. The array contains one entry per ROM type, and the values
+// in each entry dictate how to talk to the ROM.
+//
+// Supported ROMs are assumed to have the following characteristics:
+//
+// The ROM space in the machine is made up of all the same parts.
+// I.e., the space is homogeneous.
+//
+// Each chip has a byte path for data in and data out.
+//
+// Each chip has a way to identify itself.
+//
+// Each chip has a way to be reset.
+//
+// Each chip has a finite erase, write, set read-mode, and identify
+// sequence.
+//
+// The chip block size is less than or equal to 64KB.
+//
+
+//
+// Define the maximum length of certain commands.
+//
+
+#define MAXIMUM_ROM_ID_COMMAND_LENGTH 3
+#define MAXIMUM_ROM_ID_RESPONSE_LENGTH 2
+#define MAXIMUM_ROM_READ_COMMAND_LENGTH 3
+#define MAXIMUM_ROM_RESET_COMMAND_LENGTH 3
+
+//
+//
+//
+
+#define SIXTY_FOUR_KB 0x10000
+
+
+//
+// Define supported Rom types
+//
+
+typedef enum _ROM_TYPE {
+ I28F008SA,
+ Am29F010,
+ InvalidROM
+} ROM_TYPE, *PROM_TYPE;
+
+
+//
+// Define function time for erase and byte-write entries.
+//
+
+typedef ARC_STATUS (*PROMSECTORERASE) (IN PUCHAR EraseAddress);
+
+typedef ARC_STATUS (*PROMBYTEWRITE) (IN PUCHAR WriteAddress,
+ IN UCHAR WriteData);
+
+//
+// Define structure to store ROM address and byte pairs.
+//
+
+typedef struct _ABSOLUTE_ROM_COMMAND {
+ PUCHAR Address;
+ UCHAR Value;
+} ABSOLUTE_ROM_COMMAND, *PABSOLUTE_ROM_COMMAND;
+
+typedef struct _OFFSET_ROM_COMMAND {
+ ULONG Offset;
+ UCHAR Value;
+} OFFSET_ROM_COMMAND, *POFFSET_ROM_COMMAND;
+
+//
+// Define the entries in the ROM values table. These are organized for
+// memory efficiency.
+//
+
+typedef struct _ROM_VALUES {
+
+ //
+ // Microseconds to stall after most ROM commands.
+ //
+
+ UCHAR StallAmount;
+
+ //
+ // Length of the Identification command sequence.
+ //
+
+ UCHAR IdCommandLength;
+
+ //
+ // Length of the Identification response.
+ //
+
+ UCHAR IdResponseLength;
+
+ //
+ // Length of the Reset command.
+ //
+
+ UCHAR ResetCommandLength;
+
+ //
+ // Length of the Set read-mode command.
+ //
+
+ UCHAR ReadCommandLength;
+
+ //
+ // The ROM supported by this entry.
+ //
+
+ ROM_TYPE ROMType;
+
+ //
+ // Number of bytes per chip.
+ //
+
+ ULONG BytesPerChip;
+
+ //
+ // Number of bytes per block.
+ //
+
+ ULONG BytesPerBlock;
+
+ //
+ // Identification command sequence.
+ //
+ // Each step in the sequence is two bytes: address to be written,
+ // and data to be written.
+ //
+
+ ABSOLUTE_ROM_COMMAND IdCommand[MAXIMUM_ROM_ID_COMMAND_LENGTH];
+
+ //
+ // Identification response sequence.
+ //
+ // Each step in the seqeuence is two bytes: address to be read, and
+ // the byte that should be returned.
+ //
+
+ ABSOLUTE_ROM_COMMAND IdResponse[MAXIMUM_ROM_ID_RESPONSE_LENGTH];
+
+ //
+ // Reset command sequence.
+ //
+ // Each step in the sequence is two bytes: address to be written,
+ // and data to be written.
+ //
+
+ OFFSET_ROM_COMMAND ResetCommand[MAXIMUM_ROM_RESET_COMMAND_LENGTH];
+
+ //
+ // Set read-mode command sequence.
+ //
+ // Each step in the sequence is two bytes: address to be written,
+ // and data to be written.
+ //
+
+ OFFSET_ROM_COMMAND ReadCommand[MAXIMUM_ROM_READ_COMMAND_LENGTH];
+
+ //
+ // The function to be called to do a block erase.
+ //
+
+ PROMSECTORERASE SectorErase;
+
+ //
+ // The function to be called to do a byte write.
+ //
+
+ PROMBYTEWRITE ByteWrite;
+
+} ROM_VALUES, *PROM_VALUES;
+
+//
+// Define function protoypes
+//
+
+VOID
+HalpROMResetStatus(
+ IN PUCHAR Address
+ );
+
+VOID
+HalpROMSetReadMode(
+ IN PUCHAR Address
+ );
+
diff --git a/private/ntos/nthals/hal0jens/alpha/jxserp.h b/private/ntos/nthals/hal0jens/alpha/jxserp.h
new file mode 100644
index 000000000..2fc556ea3
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/jxserp.h
@@ -0,0 +1,181 @@
+/*++ BUILD Version: 0001 // Increment this if a change has global effects
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1992 Digital Equipment Corporation
+
+Module Name:
+
+ jxserp.h
+
+Abstract:
+
+ This header file defines the Jensen serial port registers.
+
+ Stolen from jazzserp.h, which is a slightly different chip-
+ it has a 16 byte fifo - we are just double buffered.
+
+Author:
+
+ David N. Cutler (davec) 28-Apr-1991
+ Miche Baker-Harvey (miche) 01-June-1992
+
+
+Revision History:
+
+--*/
+
+#ifndef _JXSERP_
+#define _JXSERP_
+
+
+//
+// Define base port numbers for serial lines inside the combo chip
+//
+
+#define COMA_PORT_BASE 0x3f8
+#define COMB_PORT_BASE 0x2f8
+
+
+//
+// Define serial port read registers structure.
+//
+
+typedef struct _SP_READ_REGISTERS {
+ UCHAR ReceiveBuffer;
+ UCHAR InterruptEnable;
+ UCHAR InterruptId;
+ UCHAR LineControl;
+ UCHAR ModemControl;
+ UCHAR LineStatus;
+ UCHAR ModemStatus;
+ UCHAR ScratchPad;
+} SP_READ_REGISTERS, *PSP_READ_REGISTERS;
+
+//
+// Define define serial port write registers structure.
+//
+
+typedef struct _SP_WRITE_REGISTERS {
+ UCHAR TransmitBuffer;
+ UCHAR InterruptEnable;
+ UCHAR FifoControl;
+ UCHAR LineControl;
+ UCHAR ModemControl;
+ UCHAR Reserved1;
+ UCHAR ModemStatus;
+ UCHAR ScratchPad;
+} SP_WRITE_REGISTERS, *PSP_WRITE_REGISTERS;
+
+//
+// Define serial port interrupt enable register structure.
+//
+
+typedef struct _SP_INTERRUPT_ENABLE {
+ UCHAR ReceiveEnable : 1;
+ UCHAR TransmitEnable : 1;
+ UCHAR LineStatusEnable : 1;
+ UCHAR ModemStatusEnable : 1;
+ UCHAR Reserved1 : 4;
+} SP_INTERRUPT_ENABLE, *PSP_INTERRUPT_ENABLE;
+
+//
+// Define serial port interrupt id register structure.
+//
+
+typedef struct _SP_INTERRUPT_ID {
+ UCHAR InterruptPending : 1;
+ UCHAR Identification : 3;
+ UCHAR Reserved1 : 2;
+ UCHAR FifoEnabled : 2; // always read as 0
+} SP_INTERRUPT_ID, *PSP_INTERRUPT_ID;
+
+//
+// Define serial port fifo control register structure.
+// This register is here for software compatibility, but there is
+// no FIFO on the 16C452
+//
+
+typedef struct _SP_FIFO_CONTROL {
+ UCHAR FifoEnable : 1;
+ UCHAR ReceiveFifoReset : 1;
+ UCHAR TransmitFifoReset : 1;
+ UCHAR DmaModeSelect : 1;
+ UCHAR Reserved1 : 2;
+ UCHAR ReceiveFifoLevel : 2;
+} SP_FIFO_CONTROL, *PSP_FIFO_CONTROL;
+
+//
+// Define serial port line control register structure.
+//
+
+typedef struct _SP_LINE_CONTROL {
+ UCHAR CharacterSize : 2;
+ UCHAR StopBits : 1;
+ UCHAR ParityEnable : 1;
+ UCHAR EvenParity : 1;
+ UCHAR StickParity : 1;
+ UCHAR SetBreak : 1;
+ UCHAR DivisorLatch : 1;
+} SP_LINE_CONTROL, *PSP_LINE_CONTROL;
+
+//
+// Line status register character size definitions.
+//
+
+#define FIVE_BITS 0x0 // five bits per character
+#define SIX_BITS 0x1 // six bits per character
+#define SEVEN_BITS 0x2 // seven bits per character
+#define EIGHT_BITS 0x3 // eight bits per character
+
+//
+// Line speed divisor definition. We get our baud rate clock
+// from the 82C106.
+//
+
+#define BAUD_RATE_9600 12 // divisor for 9600 baud
+#define BAUD_RATE_19200 6 // divisor for 19200 baud
+
+//
+// Define serial port modem control register structure.
+//
+
+typedef struct _SP_MODEM_CONTROL {
+ UCHAR DataTerminalReady : 1;
+ UCHAR RequestToSend : 1;
+ UCHAR Reserved1 : 1;
+ UCHAR Interrupt : 1;
+ UCHAR loopBack : 1;
+ UCHAR Reserved2 : 3;
+} SP_MODEM_CONTROL, *PSP_MODEM_CONTROL;
+
+//
+// Define serial port line status register structure.
+//
+
+typedef struct _SP_LINE_STATUS {
+ UCHAR DataReady : 1;
+ UCHAR OverrunError : 1;
+ UCHAR ParityError : 1;
+ UCHAR FramingError : 1;
+ UCHAR BreakIndicator : 1;
+ UCHAR TransmitHoldingEmpty : 1;
+ UCHAR TransmitEmpty : 1;
+ UCHAR ReceiveFifoError : 1;
+} SP_LINE_STATUS, *PSP_LINE_STATUS;
+
+//
+// Define serial port modem status register structure.
+//
+
+typedef struct _SP_MODEM_STATUS {
+ UCHAR DeltaClearToSend : 1;
+ UCHAR DeltaDataSetReady : 1;
+ UCHAR TrailingRingIndicator : 1;
+ UCHAR DeltaReceiveDetect : 1;
+ UCHAR ClearToSend : 1;
+ UCHAR DataSetReady : 1;
+ UCHAR RingIndicator : 1;
+ UCHAR ReceiveDetect : 1;
+} SP_MODEM_STATUS, *PSP_MODEM_STATUS;
+
+#endif // _JAZZSERP_
diff --git a/private/ntos/nthals/hal0jens/alpha/jxtime.c b/private/ntos/nthals/hal0jens/alpha/jxtime.c
new file mode 100644
index 000000000..642182045
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/jxtime.c
@@ -0,0 +1,283 @@
+#if defined(JENSEN)
+
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1992 Digital Equipment Corporation
+
+Module Name:
+
+ jxtime.c
+
+Abstract:
+
+ This module implements the HAL set/query realtime clock routines for
+ the Alpha based Jensen system
+
+Author:
+
+ David N. Cutler (davec) 5-May-1991
+ Jeff McLeman (mcleman) 3-Jun-1992
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ 13-Jul-1992 Jeff McLeman
+ use VTI access routines to access clock
+
+ 3-June-1992 Jeff McLeman
+ Adapt this module into a Jensen specific module
+
+--*/
+
+#include "halp.h"
+#include "jnsnrtc.h"
+
+
+//
+// Define forward referenced procedure prototypes.
+//
+
+UCHAR
+HalpReadClockRegister (
+ UCHAR Register
+ );
+
+VOID
+HalpWriteClockRegister (
+ UCHAR Register,
+ UCHAR Value
+ );
+
+BOOLEAN
+HalQueryRealTimeClock (
+ OUT PTIME_FIELDS TimeFields
+ )
+
+/*++
+
+Routine Description:
+
+ This routine queries the realtime clock.
+
+ N.B. This routine assumes that the caller has provided any required
+ synchronization 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.
+
+--*/
+
+{
+
+ UCHAR DataByte;
+ BOOLEAN Status;
+ KIRQL OldIrql;
+
+ KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+
+ //
+ // If the realtime clock battery is still functioning, then read
+ // the realtime clock values, and return a function value of TRUE.
+ // Otherwise, return a function value of FALSE.
+ //
+
+ DataByte = HalpReadClockRegister(RTC_CONTROL_REGISTERD);
+ if (((PRTC_CONTROL_REGISTER_D)(&DataByte))->ValidTime == 1) {
+
+ //
+ // Wait until the realtime clock is not being updated.
+ //
+
+ do {
+ DataByte = HalpReadClockRegister(RTC_CONTROL_REGISTERA);
+ } while (((PRTC_CONTROL_REGISTER_A)(&DataByte))->UpdateInProgress == 1);
+
+ //
+ // Read the realtime clock values.
+ //
+
+ TimeFields->Year = 1980 + (CSHORT)HalpReadClockRegister(RTC_YEAR);
+ TimeFields->Month = (CSHORT)HalpReadClockRegister(RTC_MONTH);
+ TimeFields->Day = (CSHORT)HalpReadClockRegister(RTC_DAY_OF_MONTH);
+ TimeFields->Weekday = (CSHORT)HalpReadClockRegister(RTC_DAY_OF_WEEK) - 1;
+ TimeFields->Hour = (CSHORT)HalpReadClockRegister(RTC_HOUR);
+ TimeFields->Minute = (CSHORT)HalpReadClockRegister(RTC_MINUTE);
+ TimeFields->Second = (CSHORT)HalpReadClockRegister(RTC_SECOND);
+ TimeFields->Milliseconds = 0;
+ Status = TRUE;
+
+ } else {
+ Status = FALSE;
+ }
+
+ KeLowerIrql(OldIrql);
+ return(Status);
+}
+
+BOOLEAN
+HalSetRealTimeClock (
+ IN PTIME_FIELDS TimeFields
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the realtime clock.
+
+ N.B. 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 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.
+
+--*/
+
+{
+ KIRQL OldIrql;
+ UCHAR DataByte;
+
+ //
+ // 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.
+ //
+
+ KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+ DataByte = HalpReadClockRegister(RTC_CONTROL_REGISTERD);
+ if (((PRTC_CONTROL_REGISTER_D)(&DataByte))->ValidTime == 1) {
+
+ //
+ // Set the realtime clock control to set the time.
+ //
+
+ DataByte = 0;
+ ((PRTC_CONTROL_REGISTER_B)(&DataByte))->HoursFormat = 1;
+ ((PRTC_CONTROL_REGISTER_B)(&DataByte))->DataMode = 1;
+ ((PRTC_CONTROL_REGISTER_B)(&DataByte))->SetTime = 1;
+ HalpWriteClockRegister(RTC_CONTROL_REGISTERB, DataByte);
+
+ //
+ // Write the realtime clock values.
+ //
+
+ HalpWriteClockRegister(RTC_YEAR, (UCHAR)(TimeFields->Year - 1980));
+ HalpWriteClockRegister(RTC_MONTH, (UCHAR)TimeFields->Month);
+ HalpWriteClockRegister(RTC_DAY_OF_MONTH, (UCHAR)TimeFields->Day);
+ HalpWriteClockRegister(RTC_DAY_OF_WEEK, (UCHAR)(TimeFields->Weekday + 1));
+ HalpWriteClockRegister(RTC_HOUR, (UCHAR)TimeFields->Hour);
+ HalpWriteClockRegister(RTC_MINUTE, (UCHAR)TimeFields->Minute);
+ HalpWriteClockRegister(RTC_SECOND, (UCHAR)TimeFields->Second);
+
+ //
+ // Set the realtime clock control to update the time.
+ // (Make sure periodic interrupt is enabled)
+ //
+
+ ((PRTC_CONTROL_REGISTER_B)(&DataByte))->SetTime = 0;
+ ((PRTC_CONTROL_REGISTER_B)(&DataByte))->TimerInterruptEnable = 1;
+ HalpWriteClockRegister(RTC_CONTROL_REGISTERB, DataByte);
+ KeLowerIrql(OldIrql);
+ return TRUE;
+
+ } else {
+ KeLowerIrql(OldIrql);
+ return FALSE;
+ }
+}
+
+UCHAR
+HalpReadClockRegister (
+ UCHAR Register
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads the specified realtime clock register.
+
+Arguments:
+
+ Register - Supplies the number of the register whose value is read.
+
+Return Value:
+
+ The value of the register is returned as the function value.
+
+--*/
+
+{
+
+ UCHAR DataByte;
+
+
+ //
+ // Read the realtime clock register value.
+ //
+
+ HalpWriteVti(RTC_APORT, Register);
+
+ DataByte = HalpReadVti(RTC_DPORT);
+
+ return DataByte;
+}
+
+VOID
+HalpWriteClockRegister (
+ UCHAR Register,
+ UCHAR Value
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes the specified value to the specified realtime
+ clock register.
+
+Arguments:
+
+ Register - Supplies the number of the register whose value is written.
+
+ Value - Supplies the value that is written to the specified register.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ //
+ // Write the realtime clock register value.
+ //
+
+ HalpWriteVti(RTC_APORT, Register);
+
+ HalpWriteVti(RTC_DPORT, Value);
+
+ return;
+}
+
+#endif
diff --git a/private/ntos/nthals/hal0jens/alpha/jxusage.c b/private/ntos/nthals/hal0jens/alpha/jxusage.c
new file mode 100644
index 000000000..75ecdcad1
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/jxusage.c
@@ -0,0 +1,48 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ jxusage.c
+
+Abstract:
+
+ The module reports the io resources in use by the alpha hal.
+
+Author:
+
+Revision History:
+
+--*/
+
+#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/hal0jens/alpha/jxvtisup.s b/private/ntos/nthals/hal0jens/alpha/jxvtisup.s
new file mode 100644
index 000000000..49a20b0a1
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/jxvtisup.s
@@ -0,0 +1,149 @@
+// TITLE("Alpha PAL funtions for HAL")
+//++
+//
+// Copyright (c) 1992 Digital Equipment Corporation
+//
+// Module Name:
+//
+// jxvtisup.s
+//
+// Abstract:
+//
+// This module implements routines to i/o to the on-board vti chip on
+// the JENSEN system board via the 64-bit super-pages.
+// Unfortunately, these routines had to be coded in assembly language
+// since it's not a particularly good idea to require a 64-bit compilation
+// mode for the otherwise 32-bit compiler. Still, the C code was awfully
+// clean.
+//
+//
+// Author:
+//
+// Joe Notarangelo 15-Jul-1992
+//
+// Environment:
+//
+// Kernel mode only.
+//
+// Revision History:
+//
+//--
+
+#include "kxalpha.h"
+
+//++
+//
+// VOID
+// outVti(
+// ULONG port
+// ULONG data
+// )
+//
+// Routine Description:
+//
+// This function uses the 64-bit super-page to write data to a port
+// of the on-board VTI combo chip for JENSEN.
+//
+// Arguments:
+//
+// port (a0) - port number on VTI chip to which to write data
+// data (a1) - data to write to the port, only low byte is significant
+// to the VTI
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(outVti)
+
+ //
+ // generate super-page address of vti, base address
+ // N.B. - upper bits must be sign extension of bit 42
+ // va<42:41> = 10 (binary) for super-page address
+ //
+
+ lda t0, 0xc01c(zero) // t0 = 0000 0000 0000 c01c
+ ldah t0, -1(t0) // t0 = ffff ffff ffff c01c
+ sll t0, 28, t0 // t0 = ffff fc01 c000 0000
+
+
+ //
+ // Shift in the port number to generate the port address we
+ // wish to access
+ // N.B. - access width is always zero = byte access for VTI
+ //
+
+ sll a0, 9, a0 // a0 << 9
+ bis t0, a0, t0 // t0 = address of VTI port
+
+
+ //
+ // Do the port write, guarantee that subsequent writes (and reads)
+ // are ordered with respect to this write and return to caller
+ //
+
+ stl a1, 0(t0) // write data to port
+ mb // guarantee write ordering
+
+ ret zero, (ra) // return
+
+ .end outVti
+
+//++
+//
+// ULONG
+// inVti(
+// ULONG port
+// )
+//
+// Routine Description:
+//
+// This function uses the 64-bit super-page to read data from a port
+// of the on-board VTI combo chip for JENSEN.
+//
+// Arguments:
+//
+// port (a0) - port number on VTI chip to which to write data
+//
+// Return Value:
+//
+// data (v0) - the data read from the VTI chip, only the low byte will
+// be valid
+//
+//--
+
+ LEAF_ENTRY(inVti)
+
+ //
+ // generate super-page address of vti, base address
+ // N.B. - upper bits must be sign extension of bit 42
+ // va<42:41> = 10 (binary) for super-page address
+ //
+
+ lda t0, 0xc01c(zero) // t0 = 0000 0000 0000 c01c
+ ldah t0, -1(t0) // t0 = ffff ffff ffff c01c
+ sll t0, 28, t0 // t0 = ffff fc01 c000 0000
+
+
+ //
+ // Shift in the port number to generate the port address we
+ // wish to access
+ // N.B. - access width for VTI is always 0 = byte access
+ //
+
+ sll a0, 9, a0 // a0 << 9
+ bis t0, a0, t0 // t0 = address of VTI port
+
+
+ //
+ // Do the super-page i/o access and return data to caller
+ //
+
+ ldl v0, 0(t0) // read data from port
+
+ ret zero, (ra) // return
+
+ .end inVti
+
diff --git a/private/ntos/nthals/hal0jens/alpha/machdep.h b/private/ntos/nthals/hal0jens/alpha/machdep.h
new file mode 100644
index 000000000..e25a3967f
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/machdep.h
@@ -0,0 +1,42 @@
+/*++
+
+Copyright (c) 1993 Digital Equipment Corporation
+
+Module Name:
+
+ machdep.h
+
+Abstract:
+
+ Dummy file so the Jensen HAL can include some things from halalpha
+
+Author:
+
+ John Vert (jvert) 17-Aug-1994
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#ifndef _MACHDEP_
+#define _MACHDEP_
+
+//
+// Define the per-processor data structures allocated in the PCR
+// for each EV4 processor.
+//
+
+typedef struct _JENSEN_PCR{
+ ULONGLONG HalpCycleCount; // 64-bit per-processor cycle count
+ EV4ProfileCount ProfileCount; // Profile counter state
+ EV4IrqStatus IrqStatusTable[MaximumIrq]; // Irq status table
+} JENSEN_PCR, *PJENSEN_PCR;
+
+#define HAL_PCR ( (PJENSEN_PCR)(&(PCR->HalReserved)) )
+
+#endif //_MACHDEP_
diff --git a/private/ntos/nthals/hal0jens/alpha/xxenvirv.c b/private/ntos/nthals/hal0jens/alpha/xxenvirv.c
new file mode 100644
index 000000000..b25b32beb
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/xxenvirv.c
@@ -0,0 +1,1451 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1992 Digital Equipment Corporation
+
+Module Name:
+
+ xxenvir.c
+
+Abstract:
+
+ This module implements the ARC firmware Environment Variable functions as
+ described in the Advanced Risc Computing Specification (Revision 1.00),
+ section 3.3.3.11, for the Alpha Jensen system.
+
+Author:
+
+ David M. Robinson (davidro) 13-June-1991
+
+
+Revision History:
+
+ Jeff McLeman (DEC) 31-Jul-1992
+
+ modify for Jensen
+
+
+ This module is for Jensen only. Jensen uses a 1 Mbyte sector eraseable
+ flash prom. Due to the long delays needed to store the environment in the
+ prom, we must implement a timer, instead of using
+ KeStallExecutionProcessor(). The prom may take up to a second to perform
+ the function, so we will go away while it is still running, and comeback
+ when it is done.
+
+--*/
+
+#include "halp.h"
+
+#if defined(JENSEN)
+#include "jxenv.h"
+#endif
+
+#include "arccodes.h"
+
+//
+// Static data.
+//
+
+UCHAR OutputString[MAXIMUM_ENVIRONMENT_VALUE];
+PUCHAR VolatileEnvironment;
+PCHAR VolatileConfig;
+PCHAR VolatileEisaData;
+PCONFIGURATION Configuration;
+
+PROMTIMER PromTimer;
+KEVENT PromEvent;
+
+//
+// Routine prototypes.
+//
+
+ARC_STATUS
+HalpEnvironmentCheckChecksum (
+ VOID
+ );
+
+ARC_STATUS
+HalpEnvironmentSetChecksum (
+ VOID
+ );
+
+ARC_STATUS
+HalpConfigurationSetChecksum (
+ VOID
+ );
+
+ARC_STATUS
+HalpEisaSetChecksum (
+ VOID
+ );
+
+ARC_STATUS
+HalpFindEnvironmentVariable (
+ IN PCHAR Variable,
+ OUT PULONG VariableIndex,
+ OUT PULONG ValueIndex
+ );
+
+VOID
+HalpInitializePromTimer(
+ IN OUT PPROMTIMER PrmTimer,
+ IN PVOID FunctionContext
+ );
+
+VOID
+HalpSetPromTimer(
+ IN PPROMTIMER PrmTimer,
+ IN ULONG MillisecondsToDelay
+ );
+
+VOID
+HalpPromDpcHandler(
+ IN PVOID SystemSpecific,
+ IN PVOID Context,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+VOID
+HalpPromDelay(
+ IN ULONG Milliseconds
+ );
+
+
+ARC_STATUS
+HalpEnvironmentInitialize (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the environment routine addresses.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG status = 0;
+
+ //
+ // Determine the ROM type in this machine
+ //
+ if (HalpROMDetermineMachineROMType() != ESUCCESS) {
+ HalDisplayString("*** Unknown ROM Type in Machine ***\n");
+ HalDisplayString(" Please contact Digital Field Services \n");
+ HalpPromDelay(10*1000);
+ HalpReboot();
+ }
+
+ //
+ // Allocate enough memory to load the environment for loaded programs.
+ //
+
+ VolatileEnvironment = ExAllocatePool(NonPagedPool, LENGTH_OF_ENVIRONMENT);
+
+ if (VolatileEnvironment == 0) {
+ status = FALSE;
+ }
+
+ HalpEnvironmentLoad();
+
+ HalpInitializePromTimer(&PromTimer,0);
+
+ return(status);
+}
+
+
+ARC_STATUS
+HalpEnvironmentCheckChecksum (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks the environment area checksum.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ If the checksum is good, ESUCCESS is returned, otherwise EIO is returned.
+
+--*/
+
+{
+ PUCHAR NvChars;
+ PNV_CONFIGURATION NvConfiguration;
+ ULONG Index;
+ ULONG Checksum1, Checksum2;
+
+ NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
+
+ //
+ // Form checksum from NVRAM data.
+ //
+
+ Checksum1 = 0;
+ NvChars = (PUCHAR)&NvConfiguration->Environment[0];
+
+ for ( Index = 0 ;
+ Index < LENGTH_OF_ENVIRONMENT;
+ Index++ ) {
+ Checksum1 += READ_PORT_UCHAR( NvChars++ );
+ }
+
+ //
+ // Reconstitute checksum and return error if no compare.
+ //
+
+ Checksum2 = (ULONG)READ_PORT_UCHAR( &NvConfiguration->Checksum2[0] ) |
+ (ULONG)READ_PORT_UCHAR( &NvConfiguration->Checksum2[1] ) << 8 |
+ (ULONG)READ_PORT_UCHAR( &NvConfiguration->Checksum2[2] ) << 16 |
+ (ULONG)READ_PORT_UCHAR( &NvConfiguration->Checksum2[3] ) << 24 ;
+
+ if (Checksum1 != Checksum2) {
+ return EIO;
+ } else {
+ return ESUCCESS;
+ }
+}
+
+
+ARC_STATUS
+HalGetEnvironmentVariable (
+ IN PCHAR Variable,
+ IN USHORT length,
+ OUT PCHAR Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine searches (not case sensitive) the non-volatile ram for
+ Variable, and if found returns a pointer to a zero terminated string that
+ contains the value, otherwise a NULL pointer is returned.
+
+
+Arguments:
+
+ Variable - Supplies a zero terminated string containing an environment
+ variable.
+ Length - Supplies the length of the vlaue buffer in bytes
+
+ Buffer - Supplies a pointer to a buffer that will recieve the
+ environment variable.
+
+Return Value:
+
+ If successful, returns a zero terminated string that is the value of
+ Variable, otherwise NULL is returned.
+
+--*/
+
+{
+ PNV_CONFIGURATION NvConfiguration;
+ ULONG VariableIndex;
+ ULONG ValueIndex;
+ ULONG Index;
+ ARC_STATUS Status;
+ KIRQL OldIrql;
+
+ //
+ // Raise IRQL to synchronize
+ //
+
+ KeRaiseIrql(DEVICE_LEVEL, &OldIrql);
+
+ NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
+
+ //
+ // If checksum is wrong, or the variable can't be found, return NULL.
+ //
+
+ if ((HalpEnvironmentCheckChecksum() != ESUCCESS) ||
+ (HalpFindEnvironmentVariable(Variable, &VariableIndex, &ValueIndex) != ESUCCESS)) {
+ Status = ENOENT;
+ } else {
+
+ //
+ // Copy value to an output string, break on zero terminator or string max.
+ //
+
+ for ( Index = 0 ; Index < length ; Index += 1 ) {
+
+ *Buffer =
+ READ_PORT_UCHAR( &NvConfiguration->Environment[ValueIndex] );
+
+ if (*Buffer== 0) {
+ break;
+ }
+
+ Buffer += 1;
+
+ ValueIndex += 1;
+
+ }
+ if (Index == length) {
+ Status = ENOMEM;
+ } else {
+ Status = ESUCCESS;
+ }
+
+ }
+
+ //
+ // Lower IRQL back to where it was
+ //
+
+ KeLowerIrql(OldIrql);
+
+ return Status;
+}
+
+
+#ifdef JENSEN
+
+ARC_STATUS
+HalSetEnvironmentVariable (
+ IN PCHAR Variable,
+ IN PCHAR Value
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets Variable (not case sensitive) to Value.
+
+ The MIPS version of this code modified the NVRAM directly.
+ For Alpha/Jensen, we have to modify the volatile area and then
+ update the PROM configuration block.
+
+
+Arguments:
+
+ Variable - Supplies a zero terminated string containing an environment
+ variable.
+
+ Value - Supplies a zero terminated string containing an environment
+ variable value.
+
+Return Value:
+
+ Returns ESUCCESS if the set completed successfully, otherwise one of
+ the following error codes is returned.
+
+ ENOSPC No space in NVRAM for set operation.
+
+ EIO Invalid Checksum.
+
+--*/
+
+{
+ PNV_CONFIGURATION NvConfiguration;
+ ULONG VariableIndex;
+ ULONG ValueIndex;
+ ULONG TopOfEnvironment;
+ PCHAR String;
+ PUCHAR VChars;
+ LONG Count;
+ CHAR Char;
+ KIRQL OldIrql;
+ ARC_STATUS Status;
+
+ //
+ // Raise Irql to Synchronize
+ //
+
+ KeRaiseIrql(DEVICE_LEVEL, &OldIrql);
+
+
+ NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
+
+ //
+ // If checksum is wrong, return EIO;
+ //
+
+ if (HalpEnvironmentCheckChecksum() != ESUCCESS) {
+ KeLowerIrql(OldIrql);
+ return EIO;
+ }
+
+
+ VChars = VolatileEnvironment;
+
+
+ //
+ // Determine the top of the environment space by looking for the first
+ // non-null character from the top.
+ //
+
+ TopOfEnvironment = LENGTH_OF_ENVIRONMENT - 1;
+ while (VChars[--TopOfEnvironment] == 0) {
+ if (TopOfEnvironment == 0) {
+ break;
+ }
+ }
+
+ //
+ // Adjust TopOfEnvironment to the first new character, unless environment
+ // space is empty.
+ //
+
+ if (TopOfEnvironment != 0) {
+ TopOfEnvironment += 2;
+ }
+
+ //
+ // Check to see if the variable already has a value.
+ //
+
+ Count = LENGTH_OF_ENVIRONMENT - TopOfEnvironment;
+
+ if (HalpFindEnvironmentVariable(Variable, &VariableIndex, &ValueIndex) == ESUCCESS) {
+
+ //
+ // Count free space, starting with the free area at the top and adding
+ // the old variable value.
+ //
+
+ for ( String = VChars + ValueIndex ;
+ *String != 0 ;
+ String++ ) {
+ Count++;
+ }
+
+ //
+ // Determine if free area is large enough to handle new value, if not
+ // return error.
+ //
+
+ for ( String = Value ; *String != 0 ; String++ ) {
+ if (Count-- == 0) {
+ KeLowerIrql(OldIrql);
+ return ENOSPC;
+ }
+ }
+
+ //
+ // Move ValueIndex to the end of the value and compress strings.
+ //
+
+ while(VChars[ValueIndex++] != 0) {
+ }
+
+ while (ValueIndex < TopOfEnvironment ) {
+ VChars[VariableIndex++] = VChars[ValueIndex++];
+ }
+
+ //
+ // Adjust new top of environment.
+ //
+
+ TopOfEnvironment = VariableIndex;
+
+ //
+ // Zero to the end.
+ //
+
+ while (VariableIndex < LENGTH_OF_ENVIRONMENT) {
+ VChars[VariableIndex++] = 0;
+ }
+
+ } else {
+
+ //
+ // Variable is new.
+ //
+
+ //
+ // Determine if free area is large enough to handle new value, if not
+ // return error.
+ //
+
+ //
+ // From the length of free space subtract new variable's length,
+ // Value's length and 2 chars, one for the '=' sign and one of the
+ // null terminator.
+ //
+
+ Count -= ( strlen(Variable) + strlen(Value) + 2 );
+
+ //
+ // Check if there is space to fit the new variable.
+ //
+
+ if (Count < 0) {
+ KeLowerIrql(OldIrql);
+ return ENOSPC;
+ }
+ }
+
+ //
+ // If Value is not zero, write new variable and value.
+ //
+
+ if (*Value != 0) {
+
+ //
+ // Write new variable, converting to upper case.
+ //
+
+ while (*Variable != 0) {
+ VChars[TopOfEnvironment++] =
+ ((*Variable >= 'a') && (*Variable <= 'z') ? (*Variable - 'a' + 'A') : *Variable);
+ Variable++;
+ }
+
+ //
+ // Write equal sign.
+ //
+
+ VChars[TopOfEnvironment++] = '=';
+
+ //
+ // Write new value.
+ //
+
+ while (*Value != 0) {
+ VChars[TopOfEnvironment++] = *Value++;
+ }
+ }
+
+ //
+ // Lower Irql back to where it was
+ //
+
+ KeLowerIrql(OldIrql);
+
+
+ /* Now update the Jensen PROM */
+
+ Status = HalpSaveConfiguration();
+
+ return Status;
+// return ESUCCESS;
+
+}
+
+#endif
+
+ARC_STATUS
+HalpFindEnvironmentVariable (
+ IN PCHAR Variable,
+ OUT PULONG VariableIndex,
+ OUT PULONG ValueIndex
+ )
+
+/*++
+
+Routine Description:
+
+ This routine searches (not case sensitive) the non-volatile ram for
+ Variable.
+
+
+Arguments:
+
+ Variable - Supplies a zero terminated string containing an environment
+ variable.
+
+Return Value:
+
+ If successful, returns ESUCCESS, otherwise returns ENOENT.
+
+--*/
+
+{
+ PNV_CONFIGURATION NvConfiguration;
+ PUCHAR String;
+ PUCHAR Environment;
+ ULONG Index;
+
+ NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
+
+ //
+ // If Variable is null, return immediately.
+ //
+
+ if (*Variable == 0) {
+ return ENOENT;
+ }
+
+ Environment = NvConfiguration->Environment;
+ Index = 0;
+
+ while (TRUE) {
+
+ //
+ // Set string to beginning of Variable.
+ //
+
+ String = Variable;
+ *VariableIndex = Index;
+
+ //
+ // Search until the end of NVRAM.
+ //
+
+ while ( Index < LENGTH_OF_ENVIRONMENT ) {
+
+ //
+ // Convert to uppercase and break if mismatch.
+ //
+
+ if ( READ_PORT_UCHAR( &Environment[Index] ) !=
+ ((*String >= 'a') &&
+ (*String <= 'z') ?
+ (*String - 'a' + 'A') : *String) ) {
+ break;
+ }
+
+ String++;
+ Index++;
+ }
+
+ //
+ // Check to see if we're at the end of the string and the variable,
+ // which means a match.
+ //
+
+ if ((*String == 0) && (READ_PORT_UCHAR( &Environment[Index] ) == '=')) {
+ *ValueIndex = ++Index;
+ return ESUCCESS;
+ }
+
+ //
+ // Move index to the start of the next variable.
+ //
+
+ while (READ_PORT_UCHAR( &Environment[Index++] ) != 0) {
+ if (Index >= LENGTH_OF_ENVIRONMENT) {
+ return ENOENT;
+ }
+ }
+ }
+}
+
+PCHAR
+HalpEnvironmentLoad (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine loads the entire environment into the volatile environment
+ area.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ If the checksum is good, a pointer to the environment in returned,
+ otherwise NULL is returned.
+
+--*/
+
+{
+ ULONG Index;
+ PUCHAR NvChars;
+ PUCHAR VChars;
+ PNV_CONFIGURATION NvConfiguration;
+
+ if (HalpEnvironmentCheckChecksum() == ESUCCESS) {
+
+ NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
+
+ //
+ // Copy the data into the volatile area.
+ //
+
+ NvChars = (PUCHAR)&NvConfiguration->Environment[0];
+ VChars = VolatileEnvironment;
+
+// READ_PORT_BUFFER_UCHAR(NvChars, VChars, LENGTH_OF_ENVIRONMENT);
+
+ for ( Index = 0 ;
+ Index < LENGTH_OF_ENVIRONMENT;
+ Index++ ) {
+ *VChars++ = READ_PORT_UCHAR( NvChars++ );
+ }
+
+ return (PCHAR)VolatileEnvironment;
+ } else {
+ return NULL;
+ }
+
+}
+
+
+ARC_STATUS
+HalpEnvironmentSetChecksum (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the environment area checksum.
+
+ For Alpha/Jensen builds, this must ONLY be called from
+ HalpEnvironmentStore, as the previous block erase & storage
+ of the entire environment variable area must have been done.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PUCHAR NvChars;
+ PNV_CONFIGURATION NvConfiguration;
+ ULONG Index;
+ ULONG Checksum;
+ KIRQL OldIrql;
+
+ NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
+
+ //
+ // Form checksum from NVRAM data.
+ //
+
+ Checksum = 0;
+ NvChars = (PUCHAR)&NvConfiguration->Environment[0];
+
+ HalpROMSetReadMode(NvChars);
+
+ KeRaiseIrql(DEVICE_LEVEL, &OldIrql);
+
+ for ( Index = 0 ;
+ Index < LENGTH_OF_ENVIRONMENT;
+ Index++ ) {
+ Checksum += READ_PORT_UCHAR( NvChars++ );
+ }
+
+ KeLowerIrql(OldIrql);
+
+ //
+ // Write environment checksum.
+ //
+
+
+ HalpROMResetStatus((PUCHAR)&NvConfiguration->Environment[0]);
+
+ if ((HalpROMByteWrite( &NvConfiguration->Checksum2[0],
+ (UCHAR)(Checksum & 0xFF)) != ESUCCESS) ||
+ (HalpROMByteWrite( &NvConfiguration->Checksum2[1],
+ (UCHAR)((Checksum >> 8) & 0xFF)) != ESUCCESS) ||
+ (HalpROMByteWrite( &NvConfiguration->Checksum2[2],
+ (UCHAR)((Checksum >> 16) & 0xFF)) != ESUCCESS) ||
+ (HalpROMByteWrite( &NvConfiguration->Checksum2[3],
+ (UCHAR)(Checksum >> 24)) != ESUCCESS)) {
+ return EIO;
+ } else {
+ return ESUCCESS;
+
+ }
+}
+
+ARC_STATUS
+HalpEnvironmentStore (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This loads the entire environment into the non-volatile environment area.
+
+ It's needed only in Jensen, which uses a segmented block-erase
+ PROM. When the code wants to store one environment variable,
+ it has to store all of them. This causes the least pertubations
+ in the firmware code.
+
+ This routine must *only* be called from HalpSaveConfiguration, which
+ does the block-erase and the store of the other part of the
+ non-volatile configuration information.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ESUCCESS if the writes were OK.
+ EIO otherwise.
+
+
+--*/
+
+{
+ ULONG Index;
+ PNV_CONFIGURATION NvConfiguration;
+ PUCHAR NvChars, VChars;
+ extern PUCHAR VolatileEnvironment; // defined in jxenvir.c
+
+
+ NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
+ VChars = VolatileEnvironment;
+ NvChars = (PUCHAR)&NvConfiguration->Environment[0];
+
+
+#if DBG
+ DbgPrint("WriteEnv: NvChars=%x, VChars=%x, loe = %x\n",
+ NvChars,VChars,LENGTH_OF_ENVIRONMENT);
+
+#endif
+
+ for (Index = 0; Index < LENGTH_OF_ENVIRONMENT; Index++) {
+ if (HalpROMByteWrite(NvChars++, *VChars++) != ESUCCESS) {
+ return EIO;
+ }
+
+ }
+
+ if (HalpEnvironmentSetChecksum() != ESUCCESS) {
+ return EIO;
+ }
+
+ return ESUCCESS;
+
+ }
+
+ARC_STATUS
+HalpSaveConfiguration (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine stores all of the configuration entries into NVRAM,
+ including the associated identifier strings and configuration data.
+
+ The Alpha/Jensen version of this code saves the entire configuration
+ structure, i.e. including the environment variables. The ARC CDS
+ + environment variables are all in one structure, and unfortunately
+ Jensen has a segmented block-erase PROM instead of an NVRAM. Doing
+ a complete save is a change that is least likely to break anything.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns ESUCCESS if the save completed successfully, otherwise one of the
+ following error codes is returned.
+
+ ENOSPC Not enough space in the NVRAM to save all of the data.
+
+ EIO Some write error happened in the PROM.
+
+--*/
+
+{
+ ULONG EntryIndex;
+ ULONG Index;
+// ULONG NumBytes;
+ PNV_CONFIGURATION NvConfiguration;
+ PUCHAR NvChars, VChars;
+ ULONG ConfigSize;
+ KIRQL OldIrql;
+ ULONG EisaSize = LENGTH_OF_EISA_DATA;
+
+
+#if DBG
+ DbgPrint("HalpSaveConfiguration: Entered\n");
+
+#endif
+ NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
+
+ ConfigSize= (
+ (sizeof(COMPRESSED_CONFIGURATION_PACKET) * NUMBER_OF_ENTRIES) +
+ LENGTH_OF_IDENTIFIER + LENGTH_OF_DATA);
+
+
+ VolatileConfig = ExAllocatePool(NonPagedPool, PAGE_SIZE);
+ if (VolatileConfig == NULL) {
+ return(ENOMEM);
+ }
+
+ VolatileEisaData = ExAllocatePool(NonPagedPool, PAGE_SIZE);
+ if (VolatileEisaData == NULL) {
+ ExFreePool(VolatileConfig);
+ return(ENOMEM);
+ }
+
+ //
+ // Copy the component structure first
+ //
+
+ VChars = VolatileConfig;
+ NvChars = (PUCHAR)NVRAM_CONFIGURATION;
+
+ KeRaiseIrql(DEVICE_LEVEL, &OldIrql);
+
+ //
+ // Copy the config data from the rom to the volatile pool
+ //
+
+#if DBG
+ DbgPrint("HalpSaveConfiguration: Reading Config data\n");
+ DbgPrint("Prom address = %x, Volatile Address = %x\n",NvChars,VChars);
+ DbgPrint("ConfigSize = %X\n",ConfigSize);
+
+#endif
+
+ for (Index = 0; Index < ConfigSize; Index++) {
+ *VChars++ = READ_PORT_UCHAR(NvChars++);
+ }
+
+
+ KeLowerIrql(OldIrql);
+
+ //
+ // Now copy the EISA data
+ //
+
+ VChars = VolatileEisaData;
+ NvChars = (PUCHAR)&NvConfiguration->EisaData[0];
+
+
+ KeRaiseIrql(DEVICE_LEVEL, &OldIrql);
+
+ //
+ // Copy the eisa data from the rom to the volatile pool
+ //
+
+#if DBG
+ DbgPrint("HalpSaveConfiguration: Reading Eisa data\n");
+ DbgPrint("Prom address = %x, Volatile Address = %x\n",NvChars,VChars);
+ DbgPrint("ConfigSize = %X\n",EisaSize);
+
+#endif
+
+ for (Index = 0; Index < EisaSize; Index++) {
+ *VChars++ = READ_PORT_UCHAR(NvChars++);
+ }
+
+
+ KeLowerIrql(OldIrql);
+
+ /*
+ * Erase the PROM block we are going to update.
+ */
+
+#if DBG
+ DbgPrint("HalpSaveConfiguration: Erasing prom block \n");
+
+#endif
+ if (HalpROMEraseBlock((PUCHAR)NVRAM_CONFIGURATION) != ESUCCESS) {
+ ExFreePool(VolatileEisaData);
+ ExFreePool(VolatileConfig);
+ return ENOSPC;
+ }
+
+
+ //
+ // Write the configuration stuff back into the rom.
+ //
+
+ VChars = VolatileConfig;
+ NvChars = (PUCHAR)NVRAM_CONFIGURATION;
+
+#if DBG
+ DbgPrint("HalpSaveConfiguration: Writing Config data\n");
+ DbgPrint("Prom address = %x, Volatile Address = %x\n",NvChars,VChars);
+ DbgPrint("ConfigSize = %X\n",ConfigSize);
+
+#endif
+ for (Index = 0; Index < ConfigSize; Index++) {
+ if (HalpROMByteWrite(NvChars++, *VChars++) != ESUCCESS) {
+ DbgPrint("HalpSaveConfig: Error Writing the Prom byte\n");
+ DbgPrint("ERROR: Prom address = %x, Volatile Address = %x\n",NvChars,VChars);
+ ExFreePool(VolatileEisaData);
+ ExFreePool(VolatileConfig);
+ return EIO;
+ }
+ }
+
+#if DBG
+ DbgPrint("HalpSaveConfig: Wrote Config data to rom\n");
+
+
+ DbgPrint("Writing Config Checksum...\n");
+
+#endif
+ if (HalpConfigurationSetChecksum() != ESUCCESS) {
+ DbgPrint("HalpSaveConfig: Error setting checksum\n");
+ HalpROMSetReadMode((PUCHAR)NvConfiguration);
+ ExFreePool(VolatileEisaData);
+ ExFreePool(VolatileConfig);
+ return EIO;
+ }
+
+
+ //
+ // Free up the pool
+ //
+
+ ExFreePool(VolatileConfig);
+
+
+ /*
+ * If the PROM status is OK then update the environment
+ * variables. If *that* is done OK too, return ESUCCESS.
+ */
+
+#if DBG
+ DbgPrint("HalpSaveConfiguration: Writing Environment Variables\n");
+
+#endif
+ if (HalpEnvironmentStore() != ESUCCESS) {
+ HalpROMSetReadMode((PUCHAR)NVRAM_CONFIGURATION);
+ return EIO;
+ }
+
+
+ //
+ // Write the eisa data back into the rom.
+ //
+
+ VChars = VolatileEisaData;
+ NvChars = (PUCHAR)&NvConfiguration->EisaData[0];
+
+
+#if DBG
+ DbgPrint("HalpSaveConfiguration: Writing Eisa Data to Prom\n");
+
+ DbgPrint("Prom address = %x, Volatile Address = %x\n",NvChars,VChars);
+ DbgPrint("ConfigSize = %X\n",EisaSize);
+
+#endif
+ for (Index = 0; Index < EisaSize; Index++) {
+ if (HalpROMByteWrite(NvChars++, *VChars++) != ESUCCESS) {
+ return EIO;
+ }
+ }
+
+
+ if (HalpEisaSetChecksum() != ESUCCESS) {
+ HalpROMSetReadMode((PUCHAR)NVRAM_CONFIGURATION);
+ return EIO;
+ }
+
+
+ //
+ // Free up the pool
+ //
+
+ ExFreePool(VolatileEisaData);
+
+ HalpROMSetReadMode((PUCHAR)NVRAM_CONFIGURATION);
+
+ //
+ // Re-read the prom block back into pool for later use
+ //
+
+#if DBG
+ DbgPrint("HalpSaveConfiguration: ReLoading Environment\n");
+
+#endif
+ HalpEnvironmentLoad();
+
+ return ESUCCESS;
+}
+
+ARC_STATUS
+HalpConfigurationSetChecksum (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the configuration checksum.
+
+ This has been coded for Alpha/Jensen. It assumes that the
+ block containing the checksum has already been erased and
+ written to, and that the status of these previous operations
+ has already been checked. This is because we have to set the
+ PROM into ReadArray mode in order to compute the checksum,
+ and this will cause previous status to be lost.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None. The PROM status is *not* checked by this function!
+
+--*/
+
+{
+ PUCHAR NvChars;
+ PNV_CONFIGURATION NvConfiguration;
+ ULONG Index;
+ ULONG Checksum1;
+ KIRQL OldIrql;
+
+#if DBG
+
+ DbgPrint("In set Config Checksum\n");
+
+#endif
+ NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
+
+
+ //
+ // Form checksum from NVRAM data.
+ //
+
+ Checksum1 = 0;
+ NvChars = (PUCHAR)NvConfiguration;
+
+ HalpROMSetReadMode(NvChars);
+
+ KeRaiseIrql(DEVICE_LEVEL, &OldIrql);
+
+ for ( Index = 0 ;
+ Index < sizeof(COMPRESSED_CONFIGURATION_PACKET) * NUMBER_OF_ENTRIES +
+ LENGTH_OF_IDENTIFIER + LENGTH_OF_DATA;
+ Index++ ) {
+ Checksum1 += READ_PORT_UCHAR( NvChars++ );
+ }
+
+ KeLowerIrql(OldIrql);
+
+ //
+ // Set checksum.
+ //
+
+ HalpROMResetStatus((PUCHAR)NvConfiguration);
+
+ if ((HalpROMByteWrite( &NvConfiguration->Checksum1[0],
+ (UCHAR)(Checksum1 & 0xFF)) != ESUCCESS) ||
+ (HalpROMByteWrite( &NvConfiguration->Checksum1[1],
+ (UCHAR)((Checksum1 >> 8) & 0xFF)) != ESUCCESS) ||
+ (HalpROMByteWrite( &NvConfiguration->Checksum1[2],
+ (UCHAR)((Checksum1 >> 16) & 0xFF)) != ESUCCESS) ||
+ (HalpROMByteWrite( &NvConfiguration->Checksum1[3],
+ (UCHAR)(Checksum1 >> 24)) != ESUCCESS)) {
+ return EIO;
+ } else {
+ return ESUCCESS;
+ }
+
+
+}
+
+ARC_STATUS
+HalpEisaSetChecksum (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the eisa data checksum.
+
+ This has been coded for Alpha/Jensen. It assumes that the
+ block containing the checksum has already been erased and
+ written to, and that the status of these previous operations
+ has already been checked. This is because we have to set the
+ PROM into ReadArray mode in order to compute the checksum,
+ and this will cause previous status to be lost.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None. The PROM status is *not* checked by this function!
+
+--*/
+
+{
+ PUCHAR NvChars;
+ PNV_CONFIGURATION NvConfiguration;
+ ULONG Index;
+ ULONG Checksum3;
+ KIRQL OldIrql;
+
+
+ NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
+
+
+ //
+ // Form checksum from NVRAM data.
+ //
+
+ Checksum3 = 0;
+ NvChars = (PUCHAR)&NvConfiguration->EisaData[0];
+
+ HalpROMSetReadMode(NvChars);
+
+ KeRaiseIrql(DEVICE_LEVEL, &OldIrql);
+
+ for ( Index = 0 ;
+ Index < LENGTH_OF_EISA_DATA;
+ Index++ ) {
+ Checksum3 += READ_PORT_UCHAR( NvChars++ );
+ }
+
+ KeLowerIrql(OldIrql);
+
+ //
+ // Set checksum.
+ //
+
+
+ HalpROMResetStatus((PUCHAR)&NvConfiguration->EisaData[0]);
+
+ if ((HalpROMByteWrite( &NvConfiguration->Checksum3[0],
+ (UCHAR)(Checksum3 & 0xFF)) != ESUCCESS) ||
+ (HalpROMByteWrite( &NvConfiguration->Checksum3[1],
+ (UCHAR)((Checksum3 >> 8) & 0xFF)) != ESUCCESS) ||
+ (HalpROMByteWrite( &NvConfiguration->Checksum3[2],
+ (UCHAR)((Checksum3 >> 16) & 0xFF)) != ESUCCESS) ||
+ (HalpROMByteWrite( &NvConfiguration->Checksum3[3],
+ (UCHAR)(Checksum3 >> 24)) != ESUCCESS)) {
+ return EIO;
+ } else {
+ return ESUCCESS;
+ }
+
+
+}
+
+VOID
+HalpInitializePromTimer(
+ IN OUT PPROMTIMER PrmTimer,
+ IN PVOID FunctionContext
+ )
+/*++
+
+Routine Description:
+
+ This routine will initialize the timer needed for waits on prom updates
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Initialize the signaling event
+ //
+
+ KeInitializeEvent(
+ &PromEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ //
+ // Initialize the timer
+ //
+
+ KeInitializeTimer(
+ &(PrmTimer->Timer)
+ );
+
+
+ //
+ // Setup the DPC that will signal the event
+ //
+
+ KeInitializeDpc(
+ &(PrmTimer->Dpc),
+ (PKDEFERRED_ROUTINE)HalpPromDpcHandler,
+ FunctionContext
+ );
+
+
+ }
+
+VOID
+HalpSetPromTimer(
+ IN PPROMTIMER PrmTimer,
+ IN ULONG MillisecondsToDelay
+ )
+/*++
+
+Routine Description:
+
+ This routine will initialize the timer needed for waits on prom updates
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ LARGE_INTEGER FireUpTime;
+
+ if (MillisecondsToDelay == 0 ) {
+ MillisecondsToDelay = 1;
+ }
+
+ FireUpTime.LowPart = -10000 * MillisecondsToDelay;
+ FireUpTime.HighPart = -1;
+
+ //
+ // Set the timer
+ //
+
+ KeSetTimer(
+ &PrmTimer->Timer,
+ FireUpTime,
+ &PrmTimer->Dpc
+ );
+}
+
+VOID
+HalpPromDpcHandler(
+ IN PVOID SystemSpecific,
+ IN PVOID Context,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+/*++
+
+Routine Description:
+
+ This routine is the DPC handler for the prom timer
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ UNREFERENCED_PARAMETER(SystemSpecific);
+ UNREFERENCED_PARAMETER(SystemArgument1);
+ UNREFERENCED_PARAMETER(SystemArgument2);
+
+
+ //
+ // Set the event so the waiting thread will continue.
+ //
+
+ KeSetEvent(
+ &PromEvent,
+ 0L,
+ FALSE
+ );
+
+ return;
+}
+
+VOID
+HalpPromDelay(
+ IN ULONG Milliseconds
+ )
+/*++
+
+Routine Description:
+
+ This routine calls the timer and waits for it to fire
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ LARGE_INTEGER TimeOut;
+ NTSTATUS status;
+
+ TimeOut.LowPart = -10000 * (Milliseconds * 2);
+ TimeOut.HighPart = -1;
+
+
+ //
+ // Start the timer
+ //
+
+ HalpSetPromTimer(&PromTimer, Milliseconds);
+
+ //
+ // Wait for the event to be signaled
+ //
+
+ status =
+ KeWaitForSingleObject(
+ &PromEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ &TimeOut
+ );
+
+ //
+ // Reset the event
+ //
+
+ KeResetEvent(
+ &PromEvent
+ );
+
+
+ return;
+}
diff --git a/private/ntos/nthals/hal0jens/alpha/xxhalp.h b/private/ntos/nthals/hal0jens/alpha/xxhalp.h
new file mode 100644
index 000000000..f77348016
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/xxhalp.h
@@ -0,0 +1,74 @@
+/*
+
+Copyright (c) 1992 Digital Equipment Corporation
+
+Module Name:
+
+ xxhalp.h
+
+Abstract:
+
+ This header file defines the private Hardware Architecture Layer (HAL)
+ Alpha non-platform specific interfaces, defines and structures.
+
+Author:
+
+ Jeff McLeman (mcleman) 09-Jul-92
+
+
+Revision History:
+
+--*/
+
+
+#ifndef _XXHALP_
+#define _XXHALP_
+
+
+
+//
+// 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)
+
+
+extern BOOLEAN LessThan16Mb;
+
+VOID
+HalpHalt(
+ VOID
+ );
+
+VOID
+HalpImb(
+ VOID
+ );
+
+VOID
+HalpMb(
+ VOID
+ );
+
+VOID
+HalpCachePcrValues(
+ VOID
+ );
+
+ULONG
+HalpRpcc(
+ VOID
+ );
+
+ULONG
+HalpGetTrapFrame (
+ VOID
+ );
+
+VOID
+HalpStallExecution(
+ ULONG Microseconds
+ );
+
+#endif // _XXHALP_
diff --git a/private/ntos/nthals/hal0jens/alpha/xxinithl.c b/private/ntos/nthals/hal0jens/alpha/xxinithl.c
new file mode 100644
index 000000000..bcef74730
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/xxinithl.c
@@ -0,0 +1,606 @@
+/*++
+
+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 an
+ Alpha machine
+
+Author:
+
+ David N. Cutler (davec) 25-Apr-1991
+ Miche Baker-Harvey (miche) 18-May-1992
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+ 28-Jul-1992 Jeff McLeman (mcleman)
+ Add code to allocate a mapping buffer for buffered DMA
+
+ 14-Jul-1992 Jeff McLeman (mcleman)
+ Add call to HalpCachePcrValues, which will call the PALcode to
+ cache values of the PCR that need fast access.
+
+ 10-Jul-1992 Jeff McLeman (mcleman)
+ Remove reference to initializing the fixed TB entries, since Alpha
+ does not have fixed TB entries.
+
+--*/
+
+#include "halp.h"
+#include "eisa.h"
+#include "jxisa.h"
+#include "jnsnrtc.h"
+
+ULONG HalpBusType = MACHINE_TYPE_EISA;
+ULONG HalpMapBufferSize;
+PHYSICAL_ADDRESS HalpMapBufferPhysicalAddress;
+
+typedef
+BOOLEAN
+KBUS_ERROR_ROUTINE (
+ IN struct _EXCEPTION_RECORD *ExceptionRecord,
+ IN struct _KEXCEPTION_FRAME *ExceptionFrame,
+ IN struct _KTRAP_FRAME *TrapFrame
+ );
+
+KBUS_ERROR_ROUTINE HalMachineCheck;
+
+//
+// HalpClockFrequency is the processor cycle counter frequency in units
+// of cycles per second (Hertz). It is a large number (e.g., 125,000,000)
+// but will still fit in a ULONG.
+//
+// HalpClockMegaHertz is the processor cycle counter frequency in units
+// of megahertz. It is a small number (e.g., 125) and is also the number
+// of cycles per microsecond. The assumption here is that clock rates will
+// always be an integral number of megahertz.
+//
+// Having the frequency available in both units avoids multiplications, or
+// especially divisions in time critical code.
+//
+
+ULONG HalpClockFrequency;
+ULONG HalpClockMegaHertz;
+
+//
+// Use the square wave mode of the PIT to measure the processor
+// speed. The timer has a frequency of 1.193MHz. We want a
+// square wave with a period of 50ms so we must initialize the
+// pit with a count of:
+// 50ms*1.193MHz = 59650 cycles
+//
+
+#define TIMER_REF_VALUE 59650
+
+ULONG
+HalpQuerySystemFrequency(
+ ULONG SampleTime
+ );
+
+BOOLEAN
+HalInitSystem (
+ IN ULONG Phase,
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ )
+
+/*++
+
+Routine Description:
+
+ This function initializes the Hardware Architecture Layer (HAL) for an
+ Alpha 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.
+
+--*/
+
+{
+ PKPRCB Prcb;
+
+ if (Phase == 0) {
+
+ //
+ // Phase 0 initialization.
+ //
+
+ //
+ // Set the time increment value.
+ //
+
+ HalpCurrentTimeIncrement = MAXIMUM_INCREMENT;
+ HalpNextTimeIncrement = MAXIMUM_INCREMENT;
+ HalpNextRateSelect = 0;
+ KeSetTimeIncrement( MAXIMUM_INCREMENT, MINIMUM_INCREMENT );
+
+ HalpMapIoSpace();
+ HalpInitializeInterrupts();
+ HalpCreateDmaStructures();
+ HalpInitializeDisplay(LoaderBlock);
+ HalpCachePcrValues();
+
+ //
+ // Fill in handlers for APIs which this HAL supports
+ //
+
+ HalQuerySystemInformation = HaliQuerySystemInformation;
+ HalSetSystemInformation = HaliSetSystemInformation;
+
+ //
+ // Establish the machine check handler for in the PCR.
+ //
+
+ PCR->MachineCheckError = HalMachineCheck;
+
+ //
+ // Verify Prcb major version number, and build options are
+ // all conforming to this binary image
+ //
+
+ Prcb = KeGetCurrentPrcb();
+#if DBG
+ if (!(Prcb->BuildType & PRCB_BUILD_DEBUG)) {
+ // This checked hal requires a checked kernel
+ KeBugCheckEx (MISMATCHED_HAL, 2, Prcb->BuildType, PRCB_BUILD_DEBUG, 0);
+ }
+#else
+ if (Prcb->BuildType & PRCB_BUILD_DEBUG) {
+ // This free hal requires a free kernel
+ KeBugCheckEx (MISMATCHED_HAL, 2, Prcb->BuildType, 0, 0);
+ }
+#endif
+#ifndef NT_UP
+ if (Prcb->BuildType & PRCB_BUILD_UNIPROCESSOR) {
+ // This MP hal requires an MP kernel
+ KeBugCheckEx (MISMATCHED_HAL, 2, Prcb->BuildType, 0, 0);
+ }
+#endif
+ if (Prcb->MajorVersion != PRCB_MAJOR_VERSION) {
+ KeBugCheckEx (MISMATCHED_HAL,
+ 1, Prcb->MajorVersion, PRCB_MAJOR_VERSION, 0);
+ }
+
+ //
+ // Now alocate a mapping buffer for buffered DMA.
+ //
+
+ LessThan16Mb = FALSE;
+
+ HalpMapBufferSize = INITIAL_MAP_BUFFER_LARGE_SIZE;
+ HalpMapBufferPhysicalAddress.LowPart =
+ HalpAllocPhysicalMemory (LoaderBlock, MAXIMUM_ISA_PHYSICAL_ADDRESS,
+ HalpMapBufferSize >> PAGE_SHIFT, TRUE);
+ HalpMapBufferPhysicalAddress.HighPart = 0;
+
+ if (!HalpMapBufferPhysicalAddress.LowPart) {
+ HalpMapBufferSize = 0;
+ }
+
+ //
+ // Setup special memory AFTER we've allocated our COMMON BUFFER!
+ //
+
+ HalpInitializeSpecialMemory( LoaderBlock );
+
+ return TRUE;
+
+ } else {
+
+ //
+ // Phase 1 initialization.
+ //
+
+ HalpCalibrateStall();
+
+ //
+ // Initialize the existing bus handlers.
+ //
+
+ HalpRegisterInternalBusHandlers();
+
+ //
+ // Allocate pool for evnironment variable support
+ //
+
+ if (HalpEnvironmentInitialize() != 0) {
+ HalDisplayString(" No pool available for Environment Variables\n");
+ }
+
+ 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.
+
+--*/
+
+{
+ 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.
+
+--*/
+
+{
+ return FALSE;
+}
+VOID
+HalpVerifyPrcbVersion ()
+{
+
+}
+
+
+ULONG
+HalpQuerySystemFrequency(
+ ULONG SampleTime
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the speed at which the system is running in hertz.
+ The system frequency is calculated by counting the number of processor
+ cycles that occur during 500ms, using the Programmable Interval Timer
+ (PIT) as the reference time. The PIT is used to generate a square
+ wave with a 50ms Period. We use the Speaker counter since we can
+ enable and disable the count from software. The output of the
+ speaker is obtained from the SIO NmiStatus register.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The system frequency in Hertz.
+
+--*/
+{
+ TIMER_CONTROL TimerControlSetup;
+ TIMER_CONTROL TimerControlReadStatus;
+ TIMER_STATUS TimerStatus;
+ NMI_STATUS NmiStatus;
+ PEISA_CONTROL controlBase;
+ ULONGLONG Count1;
+ ULONGLONG Count2;
+ ULONG NumberOfIntervals;
+ ULONG SquareWaveState = 0;
+
+// mdbfix - move this into eisa.h one day
+#define SB_READ_STATUS_ONLY 2
+
+ controlBase = HalpEisaControlBase;
+
+ //
+ // Disable the speaker counter.
+ //
+
+ *((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus);
+
+ NmiStatus.SpeakerGate = 0;
+ NmiStatus.SpeakerData = 0;
+
+ // these are MBZ when writing to NMIMISC
+ NmiStatus.RefreshToggle = 0;
+ NmiStatus.SpeakerTimer = 0;
+ NmiStatus.IochkNmi = 0;
+
+ WRITE_PORT_UCHAR(&controlBase->NmiStatus, *((PUCHAR) &NmiStatus));
+
+ //
+ // Number of Square Wave transitions to count.
+ // at 50ms period, count the number of 25ms
+ // square wave transitions for a sample reference
+ // time to against which we measure processor cycle count.
+ //
+
+ NumberOfIntervals = (SampleTime/50) * 2;
+
+ //
+ // Set the timer for counter 0 in binary mode, square wave output
+ //
+
+ TimerControlSetup.BcdMode = 0;
+ TimerControlSetup.Mode = TM_SQUARE_WAVE;
+ TimerControlSetup.SelectByte = SB_LSB_THEN_MSB;
+ TimerControlSetup.SelectCounter = SELECT_COUNTER_2;
+
+ //
+ // Set the counter for a latched read of the status.
+ // We will poll the PIT for the state of the square
+ // wave output.
+ //
+
+ TimerControlReadStatus.BcdMode = 0;
+ TimerControlReadStatus.Mode = (1 << SELECT_COUNTER_2);
+ TimerControlReadStatus.SelectByte = SB_READ_STATUS_ONLY;
+ TimerControlReadStatus.SelectCounter = SELECT_READ_BACK;
+
+
+ //
+ // Write the count value LSB and MSB for a 50ms clock period
+ //
+
+ WRITE_PORT_UCHAR( &controlBase->CommandMode1,
+ *(PUCHAR)&TimerControlSetup );
+
+ WRITE_PORT_UCHAR( &controlBase->SpeakerTone,
+ TIMER_REF_VALUE & 0xff );
+
+ WRITE_PORT_UCHAR( &controlBase->SpeakerTone,
+ (TIMER_REF_VALUE >> 8) & 0xff );
+
+ //
+ // Enable the speaker counter but disable the SPKR output signal.
+ //
+
+ *((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus);
+
+ NmiStatus.SpeakerGate = 1;
+ NmiStatus.SpeakerData = 0;
+
+ // these are MBZ when writing to NMIMISC
+ NmiStatus.RefreshToggle = 0;
+ NmiStatus.SpeakerTimer = 0;
+ NmiStatus.IochkNmi = 0;
+
+ WRITE_PORT_UCHAR(&controlBase->NmiStatus, *((PUCHAR) &NmiStatus));
+
+ //
+ // Synchronize with the counter before taking the first
+ // sample of the Processor Cycle Count (PCC). Since we
+ // are using the Square Wave Mode, wait until the next
+ // state change and then observe half a cycle before
+ // sampling.
+ //
+
+ //
+ // observe the low transition of the square wave output.
+ //
+ do {
+
+ *((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus);
+
+ } while (NmiStatus.SpeakerTimer != SquareWaveState);
+
+ SquareWaveState ^= 1;
+
+ //
+ // observe the next transition of the square wave output and then
+ // take the first cycle counter sample.
+ //
+ do {
+
+ *((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus);
+
+ } while (NmiStatus.SpeakerTimer != SquareWaveState);
+
+ Count1 = __RCC();
+
+ //
+ // Wait for the 500ms time period to pass and then take the
+ // second sample of the PCC. For a 50ms period, we have to
+ // observe eight wave transitions (25ms each).
+ //
+
+ do {
+
+ SquareWaveState ^= 1;
+
+ //
+ // wait for wave transition
+ //
+ do {
+
+ *((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus);
+
+ } while (NmiStatus.SpeakerTimer != SquareWaveState);
+
+ } while (--NumberOfIntervals);
+
+ Count2 = __RCC();
+
+ //
+ // Disable the speaker counter.
+ //
+
+ *((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus);
+
+ NmiStatus.SpeakerGate = 0;
+ NmiStatus.SpeakerData = 0;
+
+ WRITE_PORT_UCHAR(&controlBase->NmiStatus, *((PUCHAR) &NmiStatus));
+
+ //
+ // Calculate the Hz by the number of processor cycles
+ // elapsed during 1s.
+ //
+ // Hz = PCC/SampleTime * 1000ms/s
+ // = PCC * (1000/SampleTime)
+ //
+
+ // did the counter wrap? if so add 2^32
+ if (Count1 > Count2) {
+
+ Count2 += (ULONGLONG)(1 << 32);
+
+ }
+
+ return ((Count2 - Count1)*(((ULONG)1000)/SampleTime));
+}
+
+
+VOID
+HalpInitializeProcessorParameters(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine initalize the performance counter parameters
+ HalpClockFrequency and HalpClockMegaHertz based on the
+ estimated CPU speed. A 1s reference time is used for
+ the estimation.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ HalpClockFrequency = HalpQuerySystemFrequency(1000);
+ HalpClockMegaHertz = (HalpClockFrequency + 500000)/ 1000000;
+
+}
+
+#if 0
+VOID
+HalpGatherProcessorParameterStats(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine gathers statistics on the method for
+ estimating the system frequency.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Index;
+ ULONG Hertz[32];
+ ULONGLONG Mean = 0;
+ ULONGLONG Variance = 0;
+ ULONGLONG TempHertz;
+
+ //
+ // take 32 samples of estimated CPU speed,
+ // calculating the mean in the process.
+ //
+ DbgPrint("Sample\tFrequency\tMegaHertz\n\n");
+
+ for (Index = 0; Index < 32; Index++) {
+ Hertz[Index] = HalpQuerySystemFrequency(500);
+ Mean += Hertz[Index];
+
+ DbgPrint(
+ "%d\t%d\t%d\n",
+ Index,
+ Hertz[Index],
+ (ULONG)((Hertz[Index] + 500000)/1000000)
+ );
+
+ }
+
+ //
+ // calculate the mean
+ //
+
+ Mean /= 32;
+
+ //
+ // calculate the variance
+ //
+ for (Index = 0; Index < 32; Index++) {
+ TempHertz = (Mean > Hertz[Index])?
+ (Mean - Hertz[Index]) : (Hertz[Index] - Mean);
+ TempHertz = TempHertz*TempHertz;
+ Variance += TempHertz;
+ }
+
+ Variance /= 32;
+
+ DbgPrint("\nResults\n\n");
+ DbgPrint(
+ "Mean = %d\nVariance = %d\nMegaHertz (derived) = %d\n",
+ Mean,
+ Variance,
+ (Mean + 500000)/ 1000000
+ );
+
+}
+#endif
+
diff --git a/private/ntos/nthals/hal0jens/alpha/xxmemory.c b/private/ntos/nthals/hal0jens/alpha/xxmemory.c
new file mode 100644
index 000000000..131517d8a
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/xxmemory.c
@@ -0,0 +1,168 @@
+/*++
+
+Copyright (c) 1992 Digital Equipment Corporation
+
+Module Name:
+
+ xxmemory.c
+
+Abstract:
+
+ Provides routines to allow tha HAL to map physical memory
+
+Author:
+
+ Jeff McLeman (DEC) 11-June-1992
+
+Environment:
+
+ Phase 0 initialization only
+
+--*/
+
+#include "halp.h"
+
+
+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;
+ PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor;
+ 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 is contains a memory chuck
+ // 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 =
+ ((Descriptor->BasePage + 0x0f) & ~0x0f) << PAGE_SHIFT;
+
+ break;
+ }
+
+ NextMd = NextMd->Flink;
+ }
+
+ //
+ // Use the extra descriptor to define the memory at the end of the
+ // orgial 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/hal0jens/alpha/xxreturn.c b/private/ntos/nthals/hal0jens/alpha/xxreturn.c
new file mode 100644
index 000000000..911a4dc1f
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/alpha/xxreturn.c
@@ -0,0 +1,120 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1992 Digital Equipment Corporation
+
+Module Name:
+
+ xxreturn.c
+
+Abstract:
+
+ This module implements the HAL return to firmware function.
+
+ Stolen wholesale from s3return.c in ../mips.
+ Assumes that the firmware entry vector defined in the HAL spec has
+ been set up and is reachable through the System Parameter Block.
+
+Author:
+
+ David N. Cutler (davec) 21-Aug-1991
+ Miche Baker-Harvey (miche) 4-Jun-1992
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+
+VOID
+HalReturnToFirmware(
+ IN FIRMWARE_REENTRY Routine
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns control to the specified firmware routine.
+
+Arguments:
+
+ Routine - Supplies a value indicating which firmware routine to invoke.
+
+Return Value:
+
+ Does not return.
+
+Revision History:
+
+ 09-Jul-1992 Jeff McLeman (mcleman)
+ In all cases, except for ArcEnterInteractiveMode, invoke a
+ halt to restart the firmware. (Enter PAL)
+ 04-Mar-1993 Joe Mitchell (DEC)
+ Invoke a routine to call halt in ALL cases. Before calling this routine,
+ pass a value to the firmware indicating the desired function via
+ the Restart Block save area.
+
+--*/
+
+{
+ PALPHA_RESTART_SAVE_AREA AlphaSaveArea;
+ PRESTART_BLOCK RestartBlock;
+
+ //
+ // Check for a valid restart block.
+ //
+
+
+ if ((PCR->RestartBlock < (PVOID)(KSEG0_BASE) ) ||
+ (PCR->RestartBlock >= (PVOID)(KSEG2_BASE) ))
+ {
+ DbgPrint("**HalReturnToFirmware - Invalid PCR RestartBlock address\n");
+ //DbgBreakPoint();
+ HalpReboot();
+ }
+
+ RestartBlock = (PRESTART_BLOCK) PCR->RestartBlock;
+ AlphaSaveArea = (PALPHA_RESTART_SAVE_AREA) &RestartBlock->u.SaveArea;
+
+ //
+ // Reset video using NT driver's HwResetHw routine
+ //
+
+ HalpVideoReboot();
+
+ //
+ // Case on the type of return.
+ //
+
+ switch (Routine)
+ {
+ case HalHaltRoutine:
+ AlphaSaveArea->HaltReason = AXP_HALT_REASON_POWEROFF;
+ HalpReboot();
+ break;
+ case HalPowerDownRoutine:
+ AlphaSaveArea->HaltReason = AXP_HALT_REASON_POWERFAIL;
+ HalpReboot();
+ break;
+ case HalRestartRoutine:
+ AlphaSaveArea->HaltReason = AXP_HALT_REASON_RESTART;
+ HalpReboot();
+ break;
+ case HalRebootRoutine:
+ AlphaSaveArea->HaltReason = AXP_HALT_REASON_REBOOT;
+ HalpReboot();
+ break;
+ case HalInteractiveModeRoutine:
+ AlphaSaveArea->HaltReason = AXP_HALT_REASON_HALT;
+ HalpReboot();
+ break;
+ default:
+ HalDisplayString("Unknown ARCS restart function.\n");
+ DbgBreakPoint();
+ }
+
+ /* NOTREACHED */
+ HalDisplayString("Illegal return from ARCS restart function.\n");
+ DbgBreakPoint();
+}
diff --git a/private/ntos/nthals/hal0jens/drivesup.c b/private/ntos/nthals/hal0jens/drivesup.c
new file mode 100644
index 000000000..38259e5f4
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/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/hal0jens/hal.rc b/private/ntos/nthals/hal0jens/hal.rc
new file mode 100644
index 000000000..3cba4ad89
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/hal.rc
@@ -0,0 +1,11 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Hardware Abstraction Layer DLL"
+#define VER_INTERNALNAME_STR "hal.dll"
+
+#include "common.ver"
+
diff --git a/private/ntos/nthals/hal0jens/hal.src b/private/ntos/nthals/hal0jens/hal.src
new file mode 100644
index 000000000..da778bb9d
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/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/hal0jens/makefile b/private/ntos/nthals/hal0jens/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/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/hal0jens/makefile.inc b/private/ntos/nthals/hal0jens/makefile.inc
new file mode 100644
index 000000000..07fcc7d47
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/makefile.inc
@@ -0,0 +1,9 @@
+obj\alpha\hal.def: hal.src
+ rcpp -P -f hal.src -DALPHA=1 $(C_DEFINES) -g obj\alpha\hal.def
+
+$(TARGETPATH)\alpha\hal.lib: $(TARGETPATH)\alpha\hal0jens.lib
+ copy $** $@
+
+$(TARGETPATH)\alpha\hal.dll: $(TARGETPATH)\alpha\hal0jens.dll
+ copy $** $@
+ binplace $(BINPLACE_FLAGS) $@
diff --git a/private/ntos/nthals/hal0jens/sources b/private/ntos/nthals/hal0jens/sources
new file mode 100644
index 000000000..fb87d538e
--- /dev/null
+++ b/private/ntos/nthals/hal0jens/sources
@@ -0,0 +1,89 @@
+!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.
+
+
+Author:
+
+ David N. Cutler (davec) 12-Apr-1993
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=hal
+
+TARGETNAME=hal0jens
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+
+C_DEFINES=-D_JENSEN_ -DJENSEN -DEV4 -DEISA_PLATFORM
+
+!IF $(ALPHA)
+
+TARGETTYPE=HAL
+
+!ELSE
+
+TARGETTYPE=DRIVER
+
+!ENDIF
+
+INCLUDES=..\..\inc;..\..\ke;..\..\io;..\..\bldr;..\..\bldr\alpha;..\..\fw\alpha;..\..\fastfat
+
+SOURCES=
+
+ALPHA_SOURCES=hal.rc \
+ bushnd.c \
+ drivesup.c \
+ alpha\allstart.c \
+ alpha\axlbsup.c \
+ alpha\axsysint.c \
+ alpha\bios.c \
+ alpha\ev4prof.c \
+ alpha\ev4ints.s \
+ alpha\jxbeep.c \
+ alpha\jxcalstl.c \
+ alpha\jxdisp.c \
+ alpha\jxhwsup.c \
+ alpha\jxhltsup.c \
+ alpha\idle.s \
+ alpha\jxinfo.c \
+ alpha\jxinitnt.c \
+ alpha\jxioacc.s \
+ alpha\jxmapio.c \
+ alpha\jxport.c \
+ alpha\jxtime.c \
+ alpha\jxusage.c \
+ alpha\xxmemory.c \
+ alpha\axebsup.c \
+ alpha\jxcache.c \
+ alpha\halpal.s \
+ alpha\jxvtisup.s \
+ alpha\xxenvirv.c \
+ alpha\jxprom.c \
+ alpha\xxinithl.c \
+ alpha\xxreturn.c \
+ alpha\jxmchk.c \
+ alpha\jxclock.c \
+ alpha\jxintsup.s
+
+DLLDEF=obj\*\hal.def
+
+!IF $(ALPHA)
+
+NTTARGETFILES=$(TARGETPATH)\alpha\hal.lib \
+ $(TARGETPATH)\alpha\hal.dll
+
+!ENDIF