From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/ntos/nthals/hal0jens/alpha/allstart.c | 55 + private/ntos/nthals/hal0jens/alpha/axebsup.c | 786 +++++ private/ntos/nthals/hal0jens/alpha/axibsup.c | 1089 +++++++ private/ntos/nthals/hal0jens/alpha/axlbsup.c | 84 + private/ntos/nthals/hal0jens/alpha/axsysint.c | 473 +++ private/ntos/nthals/hal0jens/alpha/bios.c | 105 + private/ntos/nthals/hal0jens/alpha/ev4ints.s | 6 + private/ntos/nthals/hal0jens/alpha/ev4prof.c | 7 + private/ntos/nthals/hal0jens/alpha/halp.h | 223 ++ private/ntos/nthals/hal0jens/alpha/halpal.s | 184 ++ private/ntos/nthals/hal0jens/alpha/halvga.h | 72 + private/ntos/nthals/hal0jens/alpha/idle.s | 62 + private/ntos/nthals/hal0jens/alpha/jenfonts.h | 231 ++ private/ntos/nthals/hal0jens/alpha/jxbeep.c | 133 + private/ntos/nthals/hal0jens/alpha/jxcache.c | 521 +++ private/ntos/nthals/hal0jens/alpha/jxcalstl.c | 148 + private/ntos/nthals/hal0jens/alpha/jxclock.c | 311 ++ private/ntos/nthals/hal0jens/alpha/jxdisp.c | 752 +++++ private/ntos/nthals/hal0jens/alpha/jxenv.h | 160 + private/ntos/nthals/hal0jens/alpha/jxhalp.h | 188 ++ private/ntos/nthals/hal0jens/alpha/jxhltsup.s | 109 + private/ntos/nthals/hal0jens/alpha/jxhwsup.c | 4290 +++++++++++++++++++++++++ private/ntos/nthals/hal0jens/alpha/jxinfo.c | 142 + private/ntos/nthals/hal0jens/alpha/jxinitnt.c | 471 +++ private/ntos/nthals/hal0jens/alpha/jxintsup.s | 205 ++ private/ntos/nthals/hal0jens/alpha/jxioacc.s | 3523 ++++++++++++++++++++ private/ntos/nthals/hal0jens/alpha/jxiouser.c | 971 ++++++ private/ntos/nthals/hal0jens/alpha/jxirql.h | 133 + private/ntos/nthals/hal0jens/alpha/jxisa.h | 95 + private/ntos/nthals/hal0jens/alpha/jxmapio.c | 86 + private/ntos/nthals/hal0jens/alpha/jxmchk.c | 338 ++ private/ntos/nthals/hal0jens/alpha/jxport.c | 604 ++++ private/ntos/nthals/hal0jens/alpha/jxprof.h | 77 + private/ntos/nthals/hal0jens/alpha/jxprom.c | 1098 +++++++ private/ntos/nthals/hal0jens/alpha/jxprom.h | 218 ++ private/ntos/nthals/hal0jens/alpha/jxserp.h | 181 ++ private/ntos/nthals/hal0jens/alpha/jxtime.c | 283 ++ private/ntos/nthals/hal0jens/alpha/jxusage.c | 48 + private/ntos/nthals/hal0jens/alpha/jxvtisup.s | 149 + private/ntos/nthals/hal0jens/alpha/machdep.h | 42 + private/ntos/nthals/hal0jens/alpha/xxenvirv.c | 1451 +++++++++ private/ntos/nthals/hal0jens/alpha/xxhalp.h | 74 + private/ntos/nthals/hal0jens/alpha/xxinithl.c | 606 ++++ private/ntos/nthals/hal0jens/alpha/xxmemory.c | 168 + private/ntos/nthals/hal0jens/alpha/xxreturn.c | 120 + private/ntos/nthals/hal0jens/drivesup.c | 7 + private/ntos/nthals/hal0jens/hal.rc | 11 + private/ntos/nthals/hal0jens/hal.src | 7 + private/ntos/nthals/hal0jens/makefile | 6 + private/ntos/nthals/hal0jens/makefile.inc | 9 + private/ntos/nthals/hal0jens/sources | 89 + 51 files changed, 21201 insertions(+) create mode 100644 private/ntos/nthals/hal0jens/alpha/allstart.c create mode 100644 private/ntos/nthals/hal0jens/alpha/axebsup.c create mode 100644 private/ntos/nthals/hal0jens/alpha/axibsup.c create mode 100644 private/ntos/nthals/hal0jens/alpha/axlbsup.c create mode 100644 private/ntos/nthals/hal0jens/alpha/axsysint.c create mode 100644 private/ntos/nthals/hal0jens/alpha/bios.c create mode 100644 private/ntos/nthals/hal0jens/alpha/ev4ints.s create mode 100644 private/ntos/nthals/hal0jens/alpha/ev4prof.c create mode 100644 private/ntos/nthals/hal0jens/alpha/halp.h create mode 100644 private/ntos/nthals/hal0jens/alpha/halpal.s create mode 100644 private/ntos/nthals/hal0jens/alpha/halvga.h create mode 100644 private/ntos/nthals/hal0jens/alpha/idle.s create mode 100644 private/ntos/nthals/hal0jens/alpha/jenfonts.h create mode 100644 private/ntos/nthals/hal0jens/alpha/jxbeep.c create mode 100644 private/ntos/nthals/hal0jens/alpha/jxcache.c create mode 100644 private/ntos/nthals/hal0jens/alpha/jxcalstl.c create mode 100644 private/ntos/nthals/hal0jens/alpha/jxclock.c create mode 100644 private/ntos/nthals/hal0jens/alpha/jxdisp.c create mode 100644 private/ntos/nthals/hal0jens/alpha/jxenv.h create mode 100644 private/ntos/nthals/hal0jens/alpha/jxhalp.h create mode 100644 private/ntos/nthals/hal0jens/alpha/jxhltsup.s create mode 100644 private/ntos/nthals/hal0jens/alpha/jxhwsup.c create mode 100644 private/ntos/nthals/hal0jens/alpha/jxinfo.c create mode 100644 private/ntos/nthals/hal0jens/alpha/jxinitnt.c create mode 100644 private/ntos/nthals/hal0jens/alpha/jxintsup.s create mode 100644 private/ntos/nthals/hal0jens/alpha/jxioacc.s create mode 100644 private/ntos/nthals/hal0jens/alpha/jxiouser.c create mode 100644 private/ntos/nthals/hal0jens/alpha/jxirql.h create mode 100644 private/ntos/nthals/hal0jens/alpha/jxisa.h create mode 100644 private/ntos/nthals/hal0jens/alpha/jxmapio.c create mode 100644 private/ntos/nthals/hal0jens/alpha/jxmchk.c create mode 100644 private/ntos/nthals/hal0jens/alpha/jxport.c create mode 100644 private/ntos/nthals/hal0jens/alpha/jxprof.h create mode 100644 private/ntos/nthals/hal0jens/alpha/jxprom.c create mode 100644 private/ntos/nthals/hal0jens/alpha/jxprom.h create mode 100644 private/ntos/nthals/hal0jens/alpha/jxserp.h create mode 100644 private/ntos/nthals/hal0jens/alpha/jxtime.c create mode 100644 private/ntos/nthals/hal0jens/alpha/jxusage.c create mode 100644 private/ntos/nthals/hal0jens/alpha/jxvtisup.s create mode 100644 private/ntos/nthals/hal0jens/alpha/machdep.h create mode 100644 private/ntos/nthals/hal0jens/alpha/xxenvirv.c create mode 100644 private/ntos/nthals/hal0jens/alpha/xxhalp.h create mode 100644 private/ntos/nthals/hal0jens/alpha/xxinithl.c create mode 100644 private/ntos/nthals/hal0jens/alpha/xxmemory.c create mode 100644 private/ntos/nthals/hal0jens/alpha/xxreturn.c create mode 100644 private/ntos/nthals/hal0jens/drivesup.c create mode 100644 private/ntos/nthals/hal0jens/hal.rc create mode 100644 private/ntos/nthals/hal0jens/hal.src create mode 100644 private/ntos/nthals/hal0jens/makefile create mode 100644 private/ntos/nthals/hal0jens/makefile.inc create mode 100644 private/ntos/nthals/hal0jens/sources (limited to 'private/ntos/nthals/hal0jens') 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 + +#include + +#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 -- cgit v1.2.3