summaryrefslogtreecommitdiffstats
path: root/private/ntos/nthals/haldti/mips
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/nthals/haldti/mips')
-rw-r--r--private/ntos/nthals/haldti/mips/allstart.c56
-rw-r--r--private/ntos/nthals/haldti/mips/dtidef.h147
-rw-r--r--private/ntos/nthals/haldti/mips/halp.h179
-rw-r--r--private/ntos/nthals/haldti/mips/j4cache.s1026
-rw-r--r--private/ntos/nthals/haldti/mips/j4flshbf.s61
-rw-r--r--private/ntos/nthals/haldti/mips/j4flshio.c264
-rw-r--r--private/ntos/nthals/haldti/mips/j4prof.c291
-rw-r--r--private/ntos/nthals/haldti/mips/jxbeep.c125
-rw-r--r--private/ntos/nthals/haldti/mips/jxdisp.c246
-rw-r--r--private/ntos/nthals/haldti/mips/jxebsup.c2376
-rw-r--r--private/ntos/nthals/haldti/mips/jxenvirv.c98
-rw-r--r--private/ntos/nthals/haldti/mips/jxhalp.h105
-rw-r--r--private/ntos/nthals/haldti/mips/jxhwsup.c2024
-rw-r--r--private/ntos/nthals/haldti/mips/jxmapio.c78
-rw-r--r--private/ntos/nthals/haldti/mips/jxport.c773
-rw-r--r--private/ntos/nthals/haldti/mips/jxreturn.c89
-rw-r--r--private/ntos/nthals/haldti/mips/jxsysint.c252
-rw-r--r--private/ntos/nthals/haldti/mips/jxtime.c278
-rw-r--r--private/ntos/nthals/haldti/mips/jxusage.c48
-rw-r--r--private/ntos/nthals/haldti/mips/x4clock.s210
-rw-r--r--private/ntos/nthals/haldti/mips/x86bios.c262
-rw-r--r--private/ntos/nthals/haldti/mips/x86bios.h11
-rw-r--r--private/ntos/nthals/haldti/mips/x86lator.c11
-rw-r--r--private/ntos/nthals/haldti/mips/xxcalstl.c291
-rw-r--r--private/ntos/nthals/haldti/mips/xxclock.c171
-rw-r--r--private/ntos/nthals/haldti/mips/xxidle.s79
-rw-r--r--private/ntos/nthals/haldti/mips/xxinithl.c269
-rw-r--r--private/ntos/nthals/haldti/mips/xxinitnt.c158
-rw-r--r--private/ntos/nthals/haldti/mips/xxmemory.c170
29 files changed, 10148 insertions, 0 deletions
diff --git a/private/ntos/nthals/haldti/mips/allstart.c b/private/ntos/nthals/haldti/mips/allstart.c
new file mode 100644
index 000000000..8d81b6eb8
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/allstart.c
@@ -0,0 +1,56 @@
+/*++
+
+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:
+
+ David N. Cutler (davec) 19-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/haldti/mips/dtidef.h b/private/ntos/nthals/haldti/mips/dtidef.h
new file mode 100644
index 000000000..e105e845f
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/dtidef.h
@@ -0,0 +1,147 @@
+/*++ BUILD Version: 0005 // Increment this if a change has global effects
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ jazzdef.h
+
+Abstract:
+
+ This module is the header file that describes hardware addresses
+ for the Jazz system.
+
+Author:
+
+ David N. Cutler (davec) 26-Nov-1990
+
+Revision History:
+
+--*/
+
+#ifndef _DTIDEF_
+#define _DTIDEF_
+
+#define MACHINE_TYPE_ISA 0
+#define MACHINE_TYPE_EISA 1
+
+//
+// The MAXIMUM_MAP_BUFFER_SIZE defines the maximum map buffers which the system
+// will allocate for devices which require phyically contigous buffers.
+//
+
+//#define MAXIMUM_MAP_BUFFER_SIZE 0x40000
+#define MAXIMUM_MAP_BUFFER_SIZE 0x80000
+
+//
+// Define the initial buffer allocation size for a map buffers for systems with
+// no memory which has a physical address greater than MAXIMUM_PHYSICAL_ADDRESS.
+//
+
+//#define INITIAL_MAP_BUFFER_SMALL_SIZE 0x10000
+#define INITIAL_MAP_BUFFER_SMALL_SIZE 0x80000
+
+//
+// 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 INITIAL_MAP_BUFFER_LARGE_SIZE 0x80000
+
+//
+// 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 MAXIMUM_ISA_MAP_REGISTER 64
+
+//
+// Define the maximum physical address which can be handled by an Isa card.
+//
+
+#define MAXIMUM_ISA_PHYSICAL_ADDRESS 0x01000000
+#define MAXIMUM_PHYSICAL_ADDRESS 0x01000000
+
+
+#define COPY_BUFFER 0xFFFFFFFF
+
+#define NO_SCATTER_GATHER 0x00000001
+
+//typedef volatile struct _OLD_TRANSLATION_ENTRY {
+// ULONG PageFrame;
+// ULONG Fill;
+//} OLD_TRANSLATION_ENTRY, *POLD_TRANSLATION_ENTRY;
+//
+
+typedef volatile struct _TRANSLATION_ENTRY {
+ PVOID VirtualAddress;
+ ULONG PhysicalAddress;
+ ULONG Index;
+} TRANSLATION_ENTRY, *PTRANSLATION_ENTRY;
+
+//
+// Define physical base addresses for system mapping.
+//
+
+#define EISA_CONTROL_PHYSICAL_BASE 0x10000000 // physical base of EISA control
+#define EISA_MEMORY_PHYSICAL_BASE 0x00000000 // physical base of EISA memory
+
+////
+//// Define the size of the DMA translation table.
+////
+//#define DMA_TRANSLATION_LIMIT 0x100 // translation table limit
+
+//
+// Define EISA NMI interrupt level.
+//
+
+#define EISA_NMI_LEVEL 6
+
+//
+// Define the minimum and maximum system time increment values in 100ns units.
+//
+// N.B. these values are as close to exact values as possible given the input
+// clock of 1.19318167 hz (14.31818 / 12)
+//
+
+#define MAXIMUM_INCREMENT (99968) // Time increment in 100ns units - Approx 10 ms
+#define MINIMUM_INCREMENT (10032) // Time increment in 100ns units - Approx 1 ms
+
+//
+// Define clock constants and clock levels.
+//
+
+#define AT_BUS_OSC 14318180 // 14.31818 MHz Crystal
+#define CLOCK_LEVEL 32 // Interval clock level
+
+#if defined(R3000)
+
+#define EISA_DEVICE_LEVEL 8 // EISA bus interrupt level
+
+#endif
+
+#if defined(R4000)
+
+#define EISA_DEVICE_LEVEL 5 // EISA bus interrupt level
+
+#endif
+
+#define CLOCK2_LEVEL CLOCK_LEVEL //
+
+//
+// Define EISA device interrupt vectors.
+//
+
+#define EISA_VECTORS 32
+
+#define MAXIMUM_EISA_VECTOR (15 + EISA_VECTORS) // maximum EISA vector
+
+#endif // _DTIDEF_
diff --git a/private/ntos/nthals/haldti/mips/halp.h b/private/ntos/nthals/haldti/mips/halp.h
new file mode 100644
index 000000000..e600988b0
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/halp.h
@@ -0,0 +1,179 @@
+/*++ BUILD Version: 0003 // Increment this if a change has global effects
+
+Copyright (c) 1991 Microsoft 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
+
+
+Revision History:
+
+--*/
+
+#ifndef _HALP_
+#define _HALP_
+#include "nthal.h"
+#include "dtidef.h"
+#include "hal.h"
+#include "jxhalp.h"
+#include "xm86.h"
+#include "x86new.h"
+
+//
+// Define function prototypes.
+//
+
+ULONG
+HalpAllocateTbEntry (
+ VOID
+ );
+
+PADAPTER_OBJECT
+HalpAllocateAdapter(
+ IN ULONG MapRegistersPerChannel,
+ IN PVOID AdapterBaseVa,
+ IN PVOID ChannelNumber
+ );
+
+ULONG
+HalpAllocPhysicalMemory(
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock,
+ IN ULONG MaxPhysicalAddress,
+ IN ULONG NoPages,
+ IN BOOLEAN bAlignOn64k
+ );
+
+VOID
+HalpFreeTbEntry (
+ VOID
+ );
+
+BOOLEAN
+HalpCalibrateStall (
+ VOID
+ );
+
+VOID
+HalpClockInterrupt (
+ VOID
+ );
+
+BOOLEAN
+HalpCreateDmaStructures (
+ VOID
+ );
+
+BOOLEAN
+HalpDmaDispatch(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext
+ );
+
+BOOLEAN
+HalpGrowMapBuffers(
+ PADAPTER_OBJECT AdapterObject,
+ ULONG Amount
+ );
+
+BOOLEAN
+HalpInitializeDisplay (
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ );
+
+BOOLEAN
+HalpInitializeInterrupts (
+ VOID
+ );
+
+BOOLEAN
+HalpMapFixedTbEntries (
+ VOID
+ );
+
+BOOLEAN
+HalpMapIoSpace (
+ VOID
+ );
+
+VOID
+HalpProfileInterrupt (
+ VOID
+ );
+
+#if defined(R4000)
+
+ULONG
+HalpReadCountRegister (
+ VOID
+ );
+
+ULONG
+HalpWriteCompareRegisterAndClear (
+ IN ULONG Value
+ );
+
+#endif
+
+VOID
+HalpStallInterrupt (
+ VOID
+ );
+
+VOID HalpInitializeX86DisplayAdapter(
+ VOID
+ );
+
+VOID HalpResetX86DisplayAdapter(
+ VOID
+ );
+
+VOID
+HalpPurgeSecondaryCachePage (
+ IN PVOID BaseAddress,
+ IN ULONG Length
+ );
+
+VOID HalpProgramIntervalTimer(
+ IN ULONG IntervalCount
+ );
+
+#define HALP_IS_PHYSICAL_ADDRESS(Va) \
+ ((((ULONG)Va >= KSEG0_BASE) && ((ULONG)Va < KSEG1_BASE)) ? TRUE : FALSE)
+
+//
+// Define external references.
+//
+
+extern PHAL_RESET_DISPLAY_PARAMETERS HalpResetDisplayParameters;
+
+extern ULONG HalpCurrentTimeIncrement;
+extern ULONG HalpNextIntervalCount;
+extern ULONG HalpNextTimeIncrement;
+extern ULONG HalpNewTimeIncrement;
+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;
+
+#endif // _HALP_
diff --git a/private/ntos/nthals/haldti/mips/j4cache.s b/private/ntos/nthals/haldti/mips/j4cache.s
new file mode 100644
index 000000000..fe657e353
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/j4cache.s
@@ -0,0 +1,1026 @@
+#if defined(R4000)
+
+// TITLE("Cache Flush")
+//++
+//
+// Copyright (c) 1991 Microsoft Corporation
+//
+// Module Name:
+//
+// j4cache.s
+//
+// Abstract:
+//
+// This module implements the code necessary for cache operations on
+// a MIPS R4000.
+//
+// Author:
+//
+// David N. Cutler (davec) 19-Dec-1991
+//
+// Environment:
+//
+// Kernel mode only.
+//
+// Revision History:
+//
+//--
+
+#include "halmips.h"
+
+//
+// Define cache operations constants.
+//
+
+#define COLOR_BITS (7 << PAGE_SHIFT) // color bit (R4000 - 8kb cache)
+#define COLOR_MASK (0x7fff) // color mask (R4000 - 8kb cache)
+#define FLUSH_BASE 0xfffe0000 // flush base address
+#define PROTECTION_BITS ((1 << ENTRYLO_V) | (1 << ENTRYLO_D)) //
+
+ SBTTL("Change Color Page")
+//++
+//
+// VOID
+// HalChangeColorPage (
+// IN PVOID NewColor,
+// IN PVOID OldColor,
+// IN ULONG PageFrame
+// )
+//
+// Routine Description:
+//
+// This function changes the color of a page if the old and new colors
+// do not match.
+//
+// The algorithm used to change colors for a page is as follows:
+//
+// 1. Purge (hit/invalidate) the page from the instruction cache
+// using the old color.
+//
+// 2. Purge (hit/invalidate) the page from the data cache using
+// the old color.
+//
+// Arguments:
+//
+// NewColor (a0) - Supplies the page aligned virtual address of the
+// new color of the page to change.
+//
+// OldColor (a1) - Supplies the page aligned virtual address of the
+// old color of the page to change.
+//
+// PageFrame (a2) - Supplies the page frame number of the page that
+// is changed.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ .struct 0
+ .space 3 * 4 // fill
+CpRa: .space 4 // saved return address
+CpFrameLength: // length of stack frame
+CpA0: .space 4 // (a0)
+CpA1: .space 4 // (a1)
+CpA2: .space 4 // (a2)
+CpA3: .space 4 // (a3)
+
+ NESTED_ENTRY(HalChangeColorPage, CpFrameLength, zero)
+
+ subu sp,sp,CpFrameLength // allocate stack frame
+ sw ra,CpRa(sp) // save return address
+
+ PROLOGUE_END
+
+ and a0,a0,COLOR_BITS // isolate new color bits
+ and a1,a1,COLOR_BITS // isolate old color bits
+ beq a0,a1,10f // if eq, colors match
+ sw a1,CpA1(sp) // save old color bits
+ sw a2,CpA2(sp) // save page frame
+
+//
+// Purge the instruction cache using the old page color.
+//
+
+ move a0,a1 // set color value
+ move a1,a2 // set page frame number
+ li a2,PAGE_SIZE // set length of purge
+ jal HalPurgeIcachePage // purge instruction cache page
+
+//
+// Flush the data cache using the old page color.
+//
+
+ lw a0,CpA1(sp) // get old color bits
+ lw a1,CpA2(sp) // get page frame number
+ li a2,PAGE_SIZE // set length of purge
+ jal HalFlushDcachePage // purge data cache page
+10: lw ra,CpRa(sp) // get return address
+ addu sp,sp,CpFrameLength // deallocate stack frame
+ j ra // return
+
+ .end HalChangeColorPage
+
+ SBTTL("Flush Data Cache Page")
+//++
+//
+// VOID
+// HalFlushDcachePage (
+// IN PVOID Color,
+// IN ULONG PageFrame,
+// IN ULONG Length
+// )
+//
+// Routine Description:
+//
+// This function flushes (hit/writeback/invalidate) up to a page of data
+// from the data cache.
+//
+// Arguments:
+//
+// Color (a0) - Supplies the starting virtual address and color of the
+// data that is flushed.
+//
+// PageFrame (a1) - Supplies the page frame number of the page that
+// is flushed.
+//
+// Length (a2) - Supplies the length of the region in the page that is
+// flushed.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalFlushDcachePage)
+
+#if DBG
+
+ lw t0,KeDcacheFlushCount // get address of dcache flush count
+ lw t1,0(t0) // increment the count of flushes
+ addu t1,t1,1 //
+ sw t1,0(t0) // store result
+
+#endif
+
+ .set noreorder
+ .set noat
+ lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache policy
+ and a0,a0,COLOR_MASK // isolate color and offset bits
+ li t0,FLUSH_BASE // get base flush address
+ or t0,t0,a0 // compute color virtual address
+ sll t1,a1,ENTRYLO_PFN // shift page frame into position
+ or t1,t1,PROTECTION_BITS // merge protection bits
+ or t1,t1,v0 // merge cache policy
+ and a0,a0,0x1000 // isolate TB entry index
+ beql zero,a0,10f // if eq, first entry
+ move t2,zero // set second page table entry
+ move t2,t1 // set second page table entry
+ move t1,zero // set first page table entry
+10: mfc0 t3,wired // get TB entry index
+ lw v0,KiPcr + PcSecondLevelDcacheFillSize(zero) // get 2nd fill size
+ lw t4,KiPcr + PcFirstLevelDcacheFillSize(zero) // get 1st fill size
+ bnel zero,v0,15f // if ne, second level cache present
+ move t4,v0 // set flush block size
+ .set at
+ .set reorder
+
+//
+// Flush a page from the data cache.
+//
+
+15: DISABLE_INTERRUPTS(t5) // disable interrupts
+
+ .set noreorder
+ .set noat
+ mfc0 t6,entryhi // get current PID and VPN2
+ srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address
+ sll t7,t7,ENTRYHI_VPN2 //
+ and t6,t6,0xff << ENTRYHI_PID // isolate current PID
+ or t7,t7,t6 // merge PID with VPN2 of virtual address
+ mtc0 t7,entryhi // set VPN2 and PID for probe
+ mtc0 t1,entrylo0 // set first PTE value
+ mtc0 t2,entrylo1 // set second PTE value
+ mtc0 t3,index // set TB index value
+ nop // fill
+ tlbwi // write TB entry - 3 cycle hazzard
+ subu t6,t4,1 // compute block size minus one
+ and t7,t0,t6 // compute offset in block
+ addu a2,a2,t6 // round up to next block
+ addu a2,a2,t7 //
+ nor t6,t6,zero // complement block size minus one
+ and a2,a2,t6 // truncate length to even number
+ beq zero,a2,30f // if eq, no blocks to flush
+ and t8,t0,t6 // compute starting virtual address
+ addu t9,t8,a2 // compute ending virtual address
+ bne zero,v0,40f // if ne, second level cache present
+ subu t9,t9,t4 // compute ending loop address
+
+//
+// Flush the primary data cache only.
+//
+
+20: cache HIT_WRITEBACK_INVALIDATE_D,0(t8) // invalidate cache block
+ bne t8,t9,20b // if ne, more blocks to invalidate
+ addu t8,t8,t4 // compute next block address
+ .set at
+ .set reorder
+
+30: ENABLE_INTERRUPTS(t5) // enable interrupts
+
+ j ra // return
+
+//
+// Flush the primary and secondary data caches.
+//
+
+ .set noreorder
+ .set noat
+40: cache HIT_WRITEBACK_INVALIDATE_SD,0(t8) // invalidate cache block
+ bne t8,t9,40b // if ne, more blocks to invalidate
+ addu t8,t8,t4 // compute next block address
+ .set at
+ .set reorder
+
+ ENABLE_INTERRUPTS(t5) // enable interrupts
+
+ j ra // return
+
+ .end HalFlushDcachePage
+
+ SBTTL("Purge Data Cache Page")
+//++
+//
+// VOID
+// HalPurgeDcachePage (
+// IN PVOID Color,
+// IN ULONG PageFrame,
+// IN ULONG Length
+// )
+//
+// Routine Description:
+//
+// This function purges (hit/invalidate) up to a page of data from the
+// data cache.
+//
+// Arguments:
+//
+// Color (a0) - Supplies the starting virtual address and color of the
+// data that is purged.
+//
+// PageFrame (a1) - Supplies the page frame number of the page that
+// is purged.
+//
+// Length (a2) - Supplies the length of the region in the page that is
+// purged.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalPurgeDcachePage)
+
+#if DBG
+
+ lw t0,KeDcacheFlushCount // get address of dcache flush count
+ lw t1,0(t0) // increment the count of flushes
+ addu t1,t1,1 //
+ sw t1,0(t0) // store result
+
+#endif
+
+ .set noreorder
+ .set noat
+ lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache policy
+ and a0,a0,COLOR_MASK // isolate color bits
+ li t0,FLUSH_BASE // get base flush address
+ or t0,t0,a0 // compute color virtual address
+ sll t1,a1,ENTRYLO_PFN // shift page frame into position
+ or t1,t1,PROTECTION_BITS // merge protection bits
+ or t1,t1,v0 // merge cache policy
+ and a0,a0,0x1000 // isolate TB entry index
+ beql zero,a0,10f // if eq, first entry
+ move t2,zero // set second page table entry
+ move t2,t1 // set second page table entry
+ move t1,zero // set first page table entry
+10: mfc0 t3,wired // get TB entry index
+ lw v0,KiPcr + PcSecondLevelDcacheFillSize(zero) // get 2nd fill size
+ lw t4,KiPcr + PcFirstLevelDcacheFillSize(zero) // get 1st fill size
+ bnel zero,v0,15f // if ne, second level cache present
+ move t4,v0 // set purge block size
+ .set at
+ .set reorder
+
+//
+// Purge data from the data cache.
+//
+
+15: DISABLE_INTERRUPTS(t5) // disable interrupts
+
+ .set noreorder
+ .set noat
+ mfc0 t6,entryhi // get current PID and VPN2
+ srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address
+ sll t7,t7,ENTRYHI_VPN2 //
+ and t6,t6,0xff << ENTRYHI_PID // isolate current PID
+ or t7,t7,t6 // merge PID with VPN2 of virtual address
+ mtc0 t7,entryhi // set VPN2 and PID for probe
+ mtc0 t1,entrylo0 // set first PTE value
+ mtc0 t2,entrylo1 // set second PTE value
+ mtc0 t3,index // set TB index value
+ nop // fill
+ tlbwi // write TB entry - 3 cycle hazzard
+ subu t6,t4,1 // compute block size minus one
+ and t7,t0,t6 // compute offset in block
+ addu a2,a2,t6 // round up to next block
+ addu a2,a2,t7 //
+ nor t6,t6,zero // complement block size minus one
+ and a2,a2,t6 // truncate length to even number
+ beq zero,a2,30f // if eq, no blocks to purge
+ and t8,t0,t6 // compute starting virtual address
+ addu t9,t8,a2 // compute ending virtual address
+ bne zero,v0,40f // if ne, second level cache present
+ subu t9,t9,t4 // compute ending loop address
+
+//
+// Purge the primary data cache only.
+//
+
+20: cache HIT_INVALIDATE_D,0(t8) // invalidate cache block
+ bne t8,t9,20b // if ne, more blocks to invalidate
+ addu t8,t8,t4 // compute next block address
+ .set at
+ .set reorder
+
+30: ENABLE_INTERRUPTS(t5) // enable interrupts
+
+ j ra // return
+
+//
+// Purge the primary and secondary data caches.
+//
+
+ .set noreorder
+ .set noat
+40: cache HIT_INVALIDATE_SD,0(t8) // invalidate cache block
+ bne t8,t9,40b // if ne, more blocks to invalidate
+ addu t8,t8,t4 // compute next block address
+ .set at
+ .set reorder
+
+ ENABLE_INTERRUPTS(t5) // enable interrupts
+
+ j ra // return
+
+ .end HalPurgeDcachePage
+
+ SBTTL("Purge Instruction Cache Page")
+//++
+//
+// VOID
+// HalPurgeIcachePage (
+// IN PVOID Color,
+// IN ULONG PageFrame,
+// IN ULONG Length
+// )
+//
+// Routine Description:
+//
+// This function purges (hit/invalidate) up to a page fo data from the
+// instruction cache.
+//
+// Arguments:
+//
+// Color (a0) - Supplies the starting virtual address and color of the
+// data that is purged.
+//
+// PageFrame (a1) - Supplies the page frame number of the page that
+// is purged.
+//
+// Length (a2) - Supplies the length of the region in the page that is
+// purged.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalPurgeIcachePage)
+
+#if DBG
+
+ lw t0,KeIcacheFlushCount // get address of icache flush count
+ lw t1,0(t0) // increment the count of flushes
+ addu t1,t1,1 //
+ sw t1,0(t0) // store result
+
+#endif
+
+ .set noreorder
+ .set noat
+ lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache policy
+ and a0,a0,COLOR_MASK // isolate color bits
+ li t0,FLUSH_BASE // get base flush address
+ or t0,t0,a0 // compute color virtual address
+ sll t1,a1,ENTRYLO_PFN // shift page frame into position
+ or t1,t1,PROTECTION_BITS // merge protection bits
+ or t1,t1,v0 // merge cache policy
+ and a0,a0,0x1000 // isolate TB entry index
+ beql zero,a0,10f // if eq, first entry
+ move t2,zero // set second page table entry
+ move t2,t1 // set second page table entry
+ move t1,zero // set first page table entry
+10: mfc0 t3,wired // get TB entry index
+ lw v0,KiPcr + PcSecondLevelIcacheFillSize(zero) // get 2nd fill size
+ lw t4,KiPcr + PcFirstLevelIcacheFillSize(zero) // get 1st fill size
+ bnel zero,v0,15f // if ne, second level cache present
+ move t4,v0 // set purge block size
+ .set at
+ .set reorder
+
+//
+// Purge data from the instruction cache.
+//
+
+15: DISABLE_INTERRUPTS(t5) // disable interrupts
+
+ .set noreorder
+ .set noat
+ mfc0 t6,entryhi // get current PID and VPN2
+ srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address
+ sll t7,t7,ENTRYHI_VPN2 //
+ and t6,t6,0xff << ENTRYHI_PID // isolate current PID
+ or t7,t7,t6 // merge PID with VPN2 of virtual address
+ mtc0 t7,entryhi // set VPN2 and PID for probe
+ mtc0 t1,entrylo0 // set first PTE value
+ mtc0 t2,entrylo1 // set second PTE value
+ mtc0 t3,index // set TB index value
+ nop // fill
+ tlbwi // write TB entry - 3 cycle hazzard
+ subu t6,t4,1 // compute block size minus one
+ and t7,t0,t6 // compute offset in block
+ addu a2,a2,t6 // round up to next block
+ addu a2,a2,t7 //
+ nor t6,t6,zero // complement block size minus one
+ and a2,a2,t6 // truncate length to even number
+ beq zero,a2,30f // if eq, no blocks to purge
+ and t8,t0,t6 // compute starting virtual address
+ addu t9,t8,a2 // compute ending virtual address
+ bne zero,v0,40f // if ne, second level cache present
+ subu t9,t9,t4 // compute ending loop address
+
+//
+// Purge the primary instruction cache only.
+//
+
+20: cache HIT_INVALIDATE_I,0(t8) // invalidate cache block
+ bne t8,t9,20b // if ne, more blocks to invalidate
+ addu t8,t8,t4 // compute next block address
+ .set at
+ .set reorder
+
+30: ENABLE_INTERRUPTS(t5) // enable interrupts
+
+ j ra // return
+
+//
+// Purge the primary and secondary instruction caches.
+//
+
+ .set noreorder
+ .set noat
+40: cache HIT_INVALIDATE_SI,0(t8) // invalidate cache block
+ bne t8,t9,40b // if ne, more blocks to invalidate
+ addu t8,t8,t4 // compute next block address
+ .set at
+ .set reorder
+
+ ENABLE_INTERRUPTS(t5) // enable interrupts
+
+ j ra // return
+
+ .end HalPurgeIcachePage
+
+ SBTTL("Sweep Data Cache")
+//++
+//
+// VOID
+// HalSweepDcache (
+// VOID
+// )
+//
+// Routine Description:
+//
+// This function sweeps (index/writeback/invalidate) the entire data cache.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalSweepDcache)
+
+#if DBG
+
+ lw t0,KeDcacheFlushCount // get address of dcache flush count
+ lw t1,0(t0) // increment the count of flushes
+ addu t1,t1,1 //
+ sw t1,0(t0) // store result
+
+#endif
+
+ lw t0,KiPcr + PcFirstLevelDcacheSize(zero) // get data cache size
+ lw t1,KiPcr + PcFirstLevelDcacheFillSize(zero) // get block size
+ li a0,KSEG0_BASE // set starting index value
+ addu a1,a0,t0 // compute ending cache address
+ subu a1,a1,t1 // compute ending block address
+
+//
+// Sweep the primary data cache.
+//
+
+ .set noreorder
+ .set noat
+10: cache INDEX_WRITEBACK_INVALIDATE_D,0(a0) // writeback/invalidate on index
+ bne a0,a1,10b // if ne, more to invalidate
+ addu a0,a0,t1 // compute address of next block
+ .set at
+ .set reorder
+
+ lw t0,KiPcr + PcSecondLevelDcacheSize(zero) // get data cache size
+ lw t1,KiPcr + PcSecondLevelDcacheFillSize(zero) // get block size
+ beq zero,t1,30f // if eq, no second level cache
+ li a0,KSEG0_BASE // set starting index value
+ addu a1,a0,t0 // compute ending cache address
+ subu a1,a1,t1 // compute ending block address
+
+//
+// Sweep the secondary data cache.
+//
+
+ .set noreorder
+ .set noat
+20: cache INDEX_WRITEBACK_INVALIDATE_SD,0(a0) // writeback/invalidate on index
+ bne a0,a1,20b // if ne, more to invalidate
+ addu a0,a0,t1 // compute address of next block
+ .set at
+ .set reorder
+
+30: j ra // return
+
+ .end HalSweepDcache
+
+ SBTTL("Sweep Data Cache Range")
+//++
+//
+// VOID
+// HalSweepDcacheRange (
+// IN PVOID BaseAddress,
+// IN ULONG Length
+// )
+//
+// Routine Description:
+//
+// This function sweeps (index/writeback/invalidate) the specified range
+// of virtual addresses from the primary data cache.
+//
+// Arguments:
+//
+// BaseAddress (a0) - Supplies the base address of the range that is swept
+// from the data cache.
+//
+// Length (a1) - Supplies the length of the range that is swept from the
+// data cache.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalSweepDcacheRange)
+
+#if DBG
+
+ lw t0,KeDcacheFlushCount // get address of dcache flush count
+ lw t1,0(t0) // increment the count of flushes
+ addu t1,t1,1 //
+ sw t1,0(t0) // store result conditionally
+
+#endif
+
+ and a0,a0,COLOR_MASK // isolate color and offset bits
+ or a0,a0,KSEG0_BASE // convert to physical address
+ lw t0,KiPcr + PcFirstLevelDcacheFillSize(zero) // get block size
+ addu a1,a0,a1 // compute ending cache address
+ subu a1,a1,t0 // compute ending block address
+
+//
+// Sweep the primary data cache.
+//
+
+ .set noreorder
+ .set noat
+10: cache INDEX_WRITEBACK_INVALIDATE_D,0(a0) // writeback/invalidate on index
+ bne a0,a1,10b // if ne, more to invalidate
+ addu a0,a0,t0 // compute address of next block
+ .set at
+ .set reorder
+
+ j ra // return
+
+ .end HalSweepDcacheRange
+
+ SBTTL("Sweep Instruction Cache")
+//++
+//
+// VOID
+// HalSweepIcache (
+// VOID
+// )
+//
+// Routine Description:
+//
+// This function sweeps (index/invalidate) the entire instruction cache.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalSweepIcache)
+
+#if DBG
+
+ lw t0,KeIcacheFlushCount // get address of icache flush count
+ lw t1,0(t0) // increment the count of flushes
+ addu t1,t1,1 //
+ sw t1,0(t0) // store result
+
+#endif
+
+ lw t0,KiPcr + PcSecondLevelIcacheSize(zero) // get instruction cache size
+ lw t1,KiPcr + PcSecondLevelIcacheFillSize(zero) // get fill size
+ beq zero,t1,20f // if eq, no second level cache
+ li a0,KSEG0_BASE // set starting index value
+ addu a1,a0,t0 // compute ending cache address
+ subu a1,a1,t1 // compute ending block address
+
+//
+// Sweep the secondary instruction cache.
+//
+
+ .set noreorder
+ .set noat
+10: cache INDEX_INVALIDATE_SI,0(a0) // invalidate cache line
+ bne a0,a1,10b // if ne, more to invalidate
+ addu a0,a0,t1 // compute address of next block
+ .set at
+ .set reorder
+
+20: lw t0,KiPcr + PcFirstLevelIcacheSize(zero) // get instruction cache size
+ lw t1,KiPcr + PcFirstLevelIcacheFillSize(zero) // get fill size
+ li a0,KSEG0_BASE // set starting index value
+ addu a1,a0,t0 // compute ending cache address
+ subu a1,a1,t1 // compute ending block address
+
+//
+// Sweep the primary instruction cache.
+//
+
+ .set noreorder
+ .set noat
+30: cache INDEX_INVALIDATE_I,0(a0) // invalidate cache line
+ bne a0,a1,30b // if ne, more to invalidate
+ addu a0,a0,t1 // compute address of next block
+ .set at
+ .set reorder
+
+ j ra // return
+
+ .end HalSweepIcache
+
+ SBTTL("Sweep Instruction Cache Range")
+//++
+//
+// VOID
+// HalSweepIcacheRange (
+// IN PVOID BaseAddress,
+// IN ULONG Length
+// )
+//
+// Routine Description:
+//
+// This function sweeps (index/invalidate) the specified range of addresses
+// from the instruction cache.
+//
+// Arguments:
+//
+// BaseAddress (a0) - Supplies the base address of the range that is swept
+// from the instruction cache.
+//
+// Length (a1) - Supplies the length of the range that is swept from the
+// instruction cache.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalSweepIcacheRange)
+
+#if DBG
+
+ lw t0,KeIcacheFlushCount // get address of icache flush count
+ lw t1,0(t0) // increment the count of flushes
+ addu t1,t1,1 //
+ sw t1,0(t0) // store result
+
+#endif
+
+ and a0,a0,COLOR_MASK // isolate color and offset bits
+ or a0,a0,KSEG0_BASE // convert to physical address
+ lw t0,KiPcr + PcFirstLevelIcacheFillSize(zero) // get fill size
+ addu a1,a0,a1 // compute ending cache address
+ subu a1,a1,t0 // compute ending block address
+
+//
+// Sweep the primary instruction cache.
+//
+
+ .set noreorder
+ .set noat
+10: cache INDEX_INVALIDATE_I,0(a0) // invalidate cache line
+ bne a0,a1,10b // if ne, more to invalidate
+ addu a0,a0,t0 // compute address of next block
+ .set at
+ .set reorder
+
+ j ra // return
+
+ .end HalSweepIcacheRange
+
+ SBTTL("Zero Page")
+//++
+//
+// VOID
+// HalZeroPage (
+// IN PVOID NewColor,
+// IN PVOID OldColor,
+// IN ULONG PageFrame
+// )
+//
+// Routine Description:
+//
+// This function zeros a page of memory.
+//
+// The algorithm used to zero a page is as follows:
+//
+// 1. Purge (hit/invalidate) the page from the instruction cache
+// using the old color iff the old color is not the same as
+// the new color.
+//
+// 2. Purge (hit/invalidate) the page from the data cache using
+// the old color iff the old color is not the same as the new
+// color.
+//
+// 3. Create (create/dirty/exclusive) the page in the data cache
+// using the new color.
+//
+// 4. Write zeros to the page using the new color.
+//
+// Arguments:
+//
+// NewColor (a0) - Supplies the page aligned virtual address of the
+// new color of the page that is zeroed.
+//
+// OldColor (a1) - Supplies the page aligned virtual address of the
+// old color of the page that is zeroed.
+//
+// PageFrame (a2) - Supplies the page frame number of the page that
+// is zeroed.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ .struct 0
+ .space 3 * 4 // fill
+ZpRa: .space 4 // saved return address
+ZpFrameLength: // length of stack frame
+ZpA0: .space 4 // (a0)
+ZpA1: .space 4 // (a1)
+ZpA2: .space 4 // (a2)
+ZpA3: .space 4 // (a3)
+
+ NESTED_ENTRY(HalZeroPage, ZpFrameLength, zero)
+
+ subu sp,sp,ZpFrameLength // allocate stack frame
+ sw ra,ZpRa(sp) // save return address
+
+ PROLOGUE_END
+
+ and a0,a0,COLOR_BITS // isolate new color bits
+ and a1,a1,COLOR_BITS // isolate old color bits
+ sw a0,ZpA0(sp) // save new color bits
+ sw a1,ZpA1(sp) // save old color bits
+ sw a2,ZpA2(sp) // save page frame
+
+//
+// Purge the instruction cache using the old page color iff the old page
+// color is not equal to the new page color.
+//
+
+ beq a0,a1,10f // if eq, colors match
+ move a0,a1 // set old color value
+ move a1,a2 // set page frame number
+ li a2,PAGE_SIZE // set length of purge
+ jal HalPurgeIcachePage // purge instruction cache page
+
+//
+// Purge the data cache using the old page color iff the old page color is
+// not equal to the new page color.
+//
+
+ lw a0,ZpA1(sp) // get old color value
+ lw a1,ZpA2(sp) // get page frame number
+ li a2,PAGE_SIZE // set length of purge
+ jal HalPurgeDcachePage // purge data cache page
+
+//
+// Create dirty exclusive cache blocks and zero the data.
+//
+
+10: lw a3,ZpA0(sp) // get new color bits
+ lw a1,ZpA2(sp) // get page frame number
+
+ .set noreorder
+ .set noat
+ lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache polciy
+ li t0,FLUSH_BASE // get base flush address
+ or t0,t0,a3 // compute new color virtual address
+ sll t1,a1,ENTRYLO_PFN // shift page frame into position
+ or t1,t1,PROTECTION_BITS // merge protection bits
+ or t1,t1,v0 // merge cache policy
+ and a3,a3,0x1000 // isolate TB entry index
+ beql zero,a3,20f // if eq, first entry
+ move t2,zero // set second page table entry
+ move t2,t1 // set second page table entry
+ move t1,zero // set first page table entry
+20: mfc0 t3,wired // get TB entry index
+ lw t4,KiPcr + PcFirstLevelDcacheFillSize(zero) // get 1st fill size
+ lw v0,KiPcr + PcSecondLevelDcacheFillSize(zero) // get 2nd fill size
+ .set at
+ .set reorder
+
+ DISABLE_INTERRUPTS(t5) // disable interrupts
+
+ .set noreorder
+ .set noat
+ mfc0 t6,entryhi // get current PID and VPN2
+ srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address
+ sll t7,t7,ENTRYHI_VPN2 //
+ and t6,t6,0xff << ENTRYHI_PID // isolate current PID
+ or t7,t7,t6 // merge PID with VPN2 of virtual address
+ mtc0 t7,entryhi // set VPN2 and PID for probe
+ mtc0 t1,entrylo0 // set first PTE value
+ mtc0 t2,entrylo1 // set second PTE value
+ mtc0 t3,index // set TB index value
+ nop // fill
+ tlbwi // write TB entry - 3 cycle hazzard
+ addu t9,t0,PAGE_SIZE // compute ending address of block
+ dmtc1 zero,f0 // set write pattern
+ bne zero,v0,50f // if ne, second level cache present
+ and t8,t4,0x10 // test if 16-byte cache block
+
+//
+// Zero page in primary data cache only.
+//
+
+30: cache CREATE_DIRTY_EXCLUSIVE_D,0(t0) // create cache block
+ addu t0,t0,t4 // compute next block address
+ bne zero,t8,40f // if ne, 16-byte cache line
+ sdc1 f0,-16(t0) //
+ sdc1 f0,-24(t0) // zero 16 bytes
+ sdc1 f0,-32(t0) //
+40: bne t0,t9,30b // if ne, more blocks to zero
+ sdc1 f0,-8(t0) // zero 16 bytes
+ .set at
+ .set reorder
+
+ ENABLE_INTERRUPTS(t5) // enable interrupts
+
+ lw ra,ZpRa(sp) // get return address
+ addu sp,sp,ZpFrameLength // deallocate stack frame
+ j ra // return
+
+//
+// Zero page in primary and secondary data caches.
+//
+
+ .set noreorder
+ .set noat
+50: cache CREATE_DIRTY_EXCLUSIVE_SD,0(t0) // create secondary cache block
+ addu v1,v0,t0 // compute ending primary block address
+60: addu t0,t0,t4 // compute next block address
+ bne zero,t8,70f // if ne, 16-byte primary cache line
+ sdc1 f0,-16(t0) //
+ sdc1 f0,-24(t0) // zero 16 bytes
+ sdc1 f0,-32(t0) //
+70: bne t0,v1,60b // if ne, more primary blocks to zero
+ sdc1 f0,-8(t0) // zero 16 bytes
+ bne t0,t9,50b // if ne, more secondary blocks to zero
+ nop // fill
+ .set at
+ .set reorder
+
+ ENABLE_INTERRUPTS(t5) // enable interrupts
+
+ lw ra,ZpRa(sp) // get return address
+ addu sp,sp,ZpFrameLength // deallocate stack frame
+ j ra // return
+
+ .end HalZeroPage
+
+ SBTTL("Purge Secondary Cache Page")
+//++
+//
+// VOID
+// HalpPurgeSecondaryCachePage (
+// IN PVOID BaseAddress,
+// IN ULONG Length
+// )
+//
+// Routine Description:
+//
+// This function purges (invalidates) the specified range of addresses
+// from the secondary write through cache on an Evolution RISC PC.
+//
+// Arguments:
+//
+// BaseAddress (a0) - Supplies the base address of the page that is purged
+// from the secondary cache.
+//
+// Length (a1) - Supplies the length to purge from the secondary cache.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalpPurgeSecondaryCachePage)
+
+ lw t4,KiPcr + PcFirstLevelDcacheFillSize(zero) // get 1st fill size
+
+//
+// Purge data from the primary data cache and the secondary cache.
+//
+
+15: DISABLE_INTERRUPTS(t5) // disable interrupts
+
+ .set noreorder
+ .set noat
+ subu t6,t4,1 // compute block size minus one
+ and t7,a0,t6 // compute offset in block
+ addu a1,a1,t6 // round up to next block
+ addu a1,a1,t7 //
+ nor t6,t6,zero // complement block size minus one
+ and a1,a1,t6 // truncate length to even number
+ beq zero,a1,30f // if eq, no blocks to purge
+ and t8,a0,t6 // compute starting virtual address
+ addu t9,t8,a1 // compute ending virtual address
+ subu t9,t9,t4 // compute ending loop address
+
+20: cache HIT_INVALIDATE_D,0(t8) // invalidate primary cache block
+ lw zero,0x0(t8) // invalidate secondary cache block
+ bne t8,t9,20b // if ne, more blocks to invalidate
+ addu t8,t8,t4 // compute next block address
+ .set at
+ .set reorder
+
+30: ENABLE_INTERRUPTS(t5) // enable interrupts
+
+ j ra // return
+
+ .end HalPurgeSecondaryCachePage
+
+#endif
diff --git a/private/ntos/nthals/haldti/mips/j4flshbf.s b/private/ntos/nthals/haldti/mips/j4flshbf.s
new file mode 100644
index 000000000..ff3a32f78
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/j4flshbf.s
@@ -0,0 +1,61 @@
+#if defined(R4000)
+
+// TITLE("Miscellaneous Kernel Functions")
+//++
+//
+// Copyright (c) 1991 Microsoft Corporation
+//
+// Module Name:
+//
+// j3flshbf.s
+//
+// Abstract:
+//
+// This module implements the system dependent kernel function to flush
+// the write buffer or otherwise synchronize writes on a MIPS R4000 Jazz
+// system.
+//
+// Author:
+//
+// David N. Cutler (davec) 24-Apr-1991
+//
+// Environment:
+//
+// Kernel mode only.
+//
+// Revision History:
+//
+//--
+
+#include "halmips.h"
+
+ SBTTL("Flush Write Buffer")
+//++
+//
+// NTSTATUS
+// KeFlushWriteBuffer (
+// VOID
+// )
+//
+// Routine Description:
+//
+// This function flushes the write buffer on the current processor.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(KeFlushWriteBuffer)
+
+ sync // synchronize writes
+ j ra // return
+
+ .end KeFlushWritebuffer
+
+#endif
diff --git a/private/ntos/nthals/haldti/mips/j4flshio.c b/private/ntos/nthals/haldti/mips/j4flshio.c
new file mode 100644
index 000000000..14a757965
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/j4flshio.c
@@ -0,0 +1,264 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ j4flshio.c
+
+Abstract:
+
+
+ This module implements the system dependent kernel function to flush
+ the data cache for I/O transfers on a MIPS R4000 Jazz system.
+
+Author:
+
+ David N. Cutler (davec) 24-Apr-1991
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+
+
+extern PVOID SecondaryCachePurgeBaseAddress;
+
+VOID
+HalFlushIoBuffers (
+ IN PMDL Mdl,
+ IN BOOLEAN ReadOperation,
+ IN BOOLEAN DmaOperation
+ )
+
+/*++
+
+Routine Description:
+
+ This function flushes the I/O buffer specified by the memory descriptor
+ list from the data cache on the current processor.
+
+Arguments:
+
+ Mdl - Supplies a pointer to a memory descriptor list that describes the
+ I/O buffer location.
+
+ ReadOperation - Supplies a boolean value that determines whether the I/O
+ operation is a read into memory.
+
+ DmaOperation - Supplies a boolean value that determines whether the I/O
+ operation is a DMA operation.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG CacheSegment;
+ ULONG Length;
+ ULONG Offset;
+ KIRQL OldIrql;
+ PULONG PageFrame;
+ ULONG Source;
+
+ //
+ // The Jazz R4000 uses a write back data cache and, therefore, must be
+ // flushed on reads and writes.
+ //
+ // If the length of the I/O operation is greater than the size of the
+ // data cache, then sweep the entire data cache. Otherwise, export or
+ // purge individual pages from the data cache as appropriate.
+ //
+
+ Offset = Mdl->ByteOffset & PCR->DcacheAlignment;
+ Length = (Mdl->ByteCount +
+ PCR->DcacheAlignment + Offset) & ~PCR->DcacheAlignment;
+
+ if ((Length > PCR->FirstLevelDcacheSize) &&
+ (Length > PCR->SecondLevelDcacheSize)) {
+
+ //
+ // If the I/O operation is a DMA operation, or the I/O operation is
+ // not a DMA operation and the I/O operation is a page read operation,
+ // then sweep (index/writeback/invalidate) the entire data cache.
+ //
+
+ if ((DmaOperation != FALSE) ||
+ ((DmaOperation == FALSE) &&
+ (ReadOperation != FALSE) &&
+ ((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0))) {
+ HalSweepDcache();
+ }
+
+ //
+ // If the I/O operation is a page read, then sweep (index/invalidate)
+ // the entire instruction cache.
+ //
+
+ if ((ReadOperation != FALSE) &&
+ ((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0)) {
+ HalSweepIcache();
+ }
+
+ } else {
+
+ //
+ // Export or purge the specified pages from the data cache and
+ // instruction caches as appropriate.
+ //
+ // Compute the number of pages to flush and the starting MDL page
+ // frame address.
+ //
+
+ Offset = Mdl->ByteOffset & ~PCR->DcacheAlignment;
+ PageFrame = (PULONG)(Mdl + 1);
+ Source = ((ULONG)(Mdl->StartVa) & 0xfffff000) | Offset;
+
+ //
+ // Export or purge the specified page segments from the data and
+ // instruction caches as appropriate.
+ //
+
+ do {
+ if (Length >= (PAGE_SIZE - Offset)) {
+ CacheSegment = PAGE_SIZE - Offset;
+
+ } else {
+ CacheSegment = Length;
+ }
+
+ if (ReadOperation == FALSE) {
+
+ //
+ // The I/O operation is a write and the data only needs to
+ // to be copied back into memory if the operation is also
+ // a DMA operation.
+ //
+
+ if (DmaOperation != FALSE) {
+ HalFlushDcachePage((PVOID)Source, *PageFrame, CacheSegment);
+ }
+
+ } else {
+
+ //
+ // If the I/O operation is a DMA operation, then purge the
+ // data cache. Otherwise, is the I/O operation is a page read
+ // operation, then export the data cache.
+ //
+
+ if (DmaOperation != FALSE) {
+
+ HalPurgeDcachePage((PVOID)Source, *PageFrame, CacheSegment);
+
+ } else if ((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0) {
+ HalFlushDcachePage((PVOID)Source, *PageFrame, CacheSegment);
+ }
+
+ //
+ // If the I/O operation is a page read, then the instruction
+ // cache must be purged.
+ //
+
+ if ((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0) {
+
+ HalPurgeIcachePage((PVOID)Source, *PageFrame, CacheSegment);
+
+ }
+ }
+
+ PageFrame += 1;
+ Length -= CacheSegment;
+ Offset = 0;
+ Source += CacheSegment;
+ } while(Length != 0);
+ }
+
+ // If this is a read operation involving a DMA device, then purge the
+ // secondary write through cache by performing read operations in the
+ // appropriate range of SecondaryCachePurgeBaseAddress
+
+ if (ReadOperation != FALSE && DmaOperation != FALSE) {
+
+ volatile ULONG i;
+ volatile ULONG j;
+ ULONG PurgeOffset;
+
+ Offset = Mdl->ByteOffset & PCR->DcacheAlignment;
+
+ Length = (Mdl->ByteCount +
+ PCR->DcacheAlignment + Offset) & ~PCR->DcacheAlignment;
+
+ //
+ // Export or purge the specified pages from the data cache and
+ // instruction caches as appropriate.
+ //
+ // Compute the number of pages to flush and the starting MDL page
+ // frame address.
+ //
+
+ Offset = Mdl->ByteOffset & ~PCR->DcacheAlignment;
+ PageFrame = (PULONG)(Mdl + 1);
+ Source = ((ULONG)(Mdl->StartVa) & 0xfffff000) | Offset;
+
+ //
+ // Export or purge the specified page segments from the data and
+ // instruction caches as appropriate.
+ //
+
+ do {
+ if (Length >= (PAGE_SIZE - Offset)) {
+ CacheSegment = PAGE_SIZE - Offset;
+
+ } else {
+ CacheSegment = Length;
+ }
+
+ PurgeOffset = ((((*PageFrame)<<12) | (Source&0xfff)) & 0x7fff0);
+
+ HalpPurgeSecondaryCachePage((PVOID)((ULONG)SecondaryCachePurgeBaseAddress + PurgeOffset),CacheSegment);
+
+ PageFrame += 1;
+ Length -= CacheSegment;
+ Offset = 0;
+ Source += CacheSegment;
+ } while(Length != 0);
+ }
+
+ return;
+}
+
+ULONG
+HalGetDmaAlignmentRequirement (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the alignment requirements for DMA transfers on
+ host system.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The DMA alignment requirement is returned as the fucntion value.
+
+--*/
+
+{
+
+ return PCR->DcacheFillSize;
+}
diff --git a/private/ntos/nthals/haldti/mips/j4prof.c b/private/ntos/nthals/haldti/mips/j4prof.c
new file mode 100644
index 000000000..5c858c382
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/j4prof.c
@@ -0,0 +1,291 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ j4prof.c
+
+Abstract:
+
+ This module contains the code to start and stop the profiling interrupt
+ and to compute the profiling interval for a MIPS R4000 Jazz system.
+
+Author:
+
+ David N. Cutler (davec) 21-Feb-1991
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+// #include "ki.h"
+#include "halp.h"
+
+//
+// Define one second and round values.
+//
+
+#define ONE_SECOND (10 * 1000 * 1000) // 1 second in 100ns units
+#define ROUND_VALUE ((ONE_SECOND) - 1) // 1 second minus 100ns
+
+//
+// Define static data.
+//
+
+LARGE_INTEGER HalpPerformanceCounter;
+ULONG HalpProfileInterval = DEFAULT_PROFILE_INTERVAL;
+
+LARGE_INTEGER
+KeQueryPerformanceCounter (
+ OUT PLARGE_INTEGER Frequency OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the current performance counter value and the
+ performance counter frequency.
+
+Arguments:
+
+ Frequency - Supplies an optional pointer to a variable which receives
+ the performance counter frequency in Hertz.
+
+Return Value:
+
+ The current performance counter value is returned as the function
+ value.
+
+--*/
+
+{
+
+ ULONG CurrentCount;
+ KIRQL OldIrql;
+ LARGE_INTEGER PerformanceCounter;
+
+ //
+ // Raise IRQL to PROFILE_LEVEL, read the current value of the count
+ // register, read the performance counter, and lower IRQL to its
+ // previous value.
+ //
+ // N.B. The minimum, maximum, and default values for the profile
+ // count are chosen such that count register only overflows
+ // after about 20 seconds at 50mhz. Therefore, there is never
+ // a problem with the counter wrapping in the following code.
+ //
+
+ KeRaiseIrql(PROFILE_LEVEL, &OldIrql);
+ CurrentCount = HalpReadCountRegister();
+ PerformanceCounter = HalpPerformanceCounter;
+ KeLowerIrql(OldIrql);
+
+ //
+ // If the frequency parameter is specified, then return the performance
+ // counter frequency as the current system time frequency.
+ //
+
+ if (ARGUMENT_PRESENT(Frequency) != FALSE) {
+ Frequency->QuadPart = HalpProfileCountRate;
+ }
+
+ //
+ // Return the value of the performance counter.
+ //
+
+ PerformanceCounter.QuadPart += CurrentCount;
+ return PerformanceCounter;
+}
+
+VOID
+HalCalibratePerformanceCounter (
+ IN volatile PLONG Number
+ )
+
+/*++
+
+Routine Description:
+
+ This routine resets the performance counter value for the current
+ processor to zero. The reset is done such that the resulting value
+ is closely synchronized with other processors in the configuration.
+
+Arguments:
+
+ Number - Supplies a pointer to count of the number of processors in
+ the configuration.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Write the compare register, clear the count register, and zero the
+ // performance counter for the current processor.
+ //
+
+ HalpWriteCompareRegisterAndClear(DEFAULT_PROFILE_COUNT);
+ HalpPerformanceCounter.QuadPart = 0;
+ return;
+}
+
+ULONG
+HalSetProfileInterval (
+ IN ULONG Interval
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the profile interrupt interval.
+
+Arguments:
+
+ Interval - Supplies the desired profile interval in 100ns units.
+
+Return Value:
+
+ The actual profile interval.
+
+--*/
+
+{
+
+ LARGE_INTEGER TempValue;
+
+ //
+ // If the specified profile interval is less that the minimum profile
+ // interval or greater than the maximum profile interval, then set the
+ // profile interval to the minimum or maximum as appropriate.
+ //
+
+ if (Interval < MINIMUM_PROFILE_INTERVAL) {
+ Interval = MINIMUM_PROFILE_INTERVAL;
+
+ } else if (Interval > MAXIMUM_PROFILE_INTERVAL) {
+ Interval = MAXIMUM_PROFILE_INTERVAL;
+ }
+
+ //
+ // First compute the profile count value and then back calculate the
+ // actual profile interval.
+ //
+
+ TempValue.QuadPart = Int32x32To64(HalpProfileCountRate, Interval);
+ TempValue.QuadPart += ROUND_VALUE;
+ TempValue = RtlExtendedLargeIntegerDivide(TempValue, ONE_SECOND, NULL);
+ TempValue.QuadPart = Int32x32To64(TempValue.LowPart, ONE_SECOND);
+ TempValue = RtlExtendedLargeIntegerDivide(TempValue, HalpProfileCountRate, NULL);
+ HalpProfileInterval = TempValue.LowPart;
+ return HalpProfileInterval;
+}
+
+VOID
+HalStartProfileInterrupt (
+ KPROFILE_SOURCE Source
+ )
+
+/*++
+
+Routine Description:
+
+ This routine computes the profile count value, writes the compare
+ register, clears the count register, and updates the performance
+ counter.
+
+ N.B. This routine must be called at PROFILE_LEVEL while holding the
+ profile lock.
+
+Arguments:
+
+ Source - Supplies the profile source.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG PreviousCount;
+ LARGE_INTEGER TempValue;
+
+ //
+ // Compute the profile count from the current profile interval.
+ //
+
+ TempValue.QuadPart = Int32x32To64(HalpProfileCountRate,
+ HalpProfileInterval);
+
+ TempValue.QuadPart += ROUND_VALUE;
+ TempValue = RtlExtendedLargeIntegerDivide(TempValue, ONE_SECOND, NULL);
+
+ //
+ // Write the compare register and clear the count register.
+ //
+
+ PreviousCount = HalpWriteCompareRegisterAndClear(TempValue.LowPart);
+
+ //
+ // Update the performance counter by adding in the previous count value.
+ //
+
+ HalpPerformanceCounter.QuadPart += PreviousCount;
+ return;
+}
+
+VOID
+HalStopProfileInterrupt (
+ KPROFILE_SOURCE Source
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the default count value, writes the compare
+ register, clears the count register, and updates the performance
+ counter.
+
+ N.B. This routine must be called at PROFILE_LEVEL while holding the
+ profile lock.
+
+Arguments:
+
+ Sourve - Supplies the profile source.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG PreviousCount;
+
+ //
+ // Write the compare register and clear the count register.
+ //
+
+ PreviousCount = HalpWriteCompareRegisterAndClear(DEFAULT_PROFILE_COUNT);
+
+ //
+ // Update the performance counter by adding in the previous count value.
+ //
+
+ HalpPerformanceCounter.QuadPart += PreviousCount;
+ return;
+}
diff --git a/private/ntos/nthals/haldti/mips/jxbeep.c b/private/ntos/nthals/haldti/mips/jxbeep.c
new file mode 100644
index 000000000..cb04082f4
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/jxbeep.c
@@ -0,0 +1,125 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ jxbeep.c
+
+Abstract:
+
+ This module implements the HAL speaker "beep" routines for a MIPS
+ system.
+
+Author:
+
+
+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_REGISTER_UCHAR(&controlBase->NmiStatus);
+
+ NmiStatus.SpeakerGate = 0;
+ NmiStatus.SpeakerData = 0;
+
+ WRITE_REGISTER_UCHAR(&controlBase->NmiStatus, *((PUCHAR) &NmiStatus));
+
+ if (Frequency == 0) {
+ KeLowerIrql(oldIrql);
+ return(TRUE);
+ }
+
+ //
+ // Calculate the new counter value.
+ //
+
+ newCount = (AT_BUS_OSC/12) / 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_REGISTER_UCHAR(&controlBase->CommandMode1, *((PUCHAR) &timerControl));
+
+ //
+ // Set the speaker timer to the correct mode.
+ //
+
+ WRITE_REGISTER_UCHAR(&controlBase->SpeakerTone, (UCHAR)(newCount & 0xff));
+ WRITE_REGISTER_UCHAR(&controlBase->SpeakerTone, (UCHAR)(newCount >> 8));
+
+ //
+ // Start the speaker.
+ //
+
+ NmiStatus.SpeakerGate = 1;
+ NmiStatus.SpeakerData = 1;
+
+ WRITE_REGISTER_UCHAR(&controlBase->NmiStatus, *((PUCHAR) &NmiStatus));
+ KeLowerIrql(oldIrql);
+ return(TRUE);
+}
diff --git a/private/ntos/nthals/haldti/mips/jxdisp.c b/private/ntos/nthals/haldti/mips/jxdisp.c
new file mode 100644
index 000000000..3225a0a4f
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/jxdisp.c
@@ -0,0 +1,246 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ jxdisp.c
+
+Abstract:
+
+ This module implements the HAL display initialization and output routines
+ for a MIPS R3000 or R4000 Jazz system.
+
+Author:
+
+ Andre Vachon (andreva) 09-May-1992
+ David N. Cutler (davec) 27-Apr-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "eisa.h"
+#include "stdio.h"
+#include "string.h"
+
+#define CSI (CHAR)0x9b
+
+extern ULONG IoSpaceAlreadyMapped;
+
+static CHAR DisplayInitializationString[] = {CSI,'3','7',';','4','4','m',CSI,'2','J',0};
+static CHAR CarriageReturnString[] = {13,0};
+
+static ULONG HalOwnsDisplay = FALSE;
+static ULONG DisplayFile;
+
+PHAL_RESET_DISPLAY_PARAMETERS HalpResetDisplayParameters;
+
+
+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.
+
+--*/
+
+{
+ ArcClose(DisplayFile);
+ HalOwnsDisplay = FALSE;
+
+ HalpResetDisplayParameters = ResetDisplayParameters;
+
+ return;
+}
+
+
+VOID
+HalDisplayString (
+ PUCHAR String
+ )
+
+/*++
+
+Routine Description:
+
+ This routine displays a character string on the display screen.
+
+Arguments:
+
+ String - Supplies a pointer to the characters that are to be displayed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Count;
+
+ if (IoSpaceAlreadyMapped == FALSE) {
+ HalpMapIoSpace();
+ HalpInitializeX86DisplayAdapter();
+ IoSpaceAlreadyMapped = TRUE;
+ }
+
+ if (HalOwnsDisplay==FALSE) {
+
+ if (HalpResetDisplayParameters != NULL) {
+ (HalpResetDisplayParameters)(80,25);
+ }
+
+ HalpResetX86DisplayAdapter();
+ ArcOpen(ArcGetEnvironmentVariable("ConsoleOut"),ArcOpenWriteOnly,&DisplayFile);
+ ArcWrite(DisplayFile,DisplayInitializationString,strlen(DisplayInitializationString),&Count);
+ HalOwnsDisplay=TRUE;
+ }
+
+ ArcWrite(DisplayFile,String,strlen(String),&Count);
+ ArcWrite(DisplayFile,CarriageReturnString,strlen(CarriageReturnString),&Count);
+ 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.
+
+--*/
+
+{
+ ARC_DISPLAY_STATUS *DisplayStatus;
+
+ //
+ // Get the display parameter values and return.
+ //
+
+ //
+ // If the HAL does not already own the display, then print an empty string.
+ // This guarantees that the file descriptor DisplayFile is valid.
+ //
+
+ if (!HalOwnsDisplay) {
+ HalDisplayString("");
+ }
+
+ //
+ // Make firmware call to get the display's current status
+ //
+
+ DisplayStatus = ArcGetDisplayStatus(DisplayFile);
+
+ *WidthInCharacters = DisplayStatus->CursorMaxXPosition;
+ *HeightInLines = DisplayStatus->CursorMaxYPosition;
+ *CursorColumn = DisplayStatus->CursorXPosition;
+ *CursorRow = DisplayStatus->CursorYPosition;
+
+ 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.
+
+--*/
+
+{
+ CHAR SetCursorPositionString[20];
+ ULONG Count;
+
+ //
+ // Set the display parameter values and return.
+ //
+
+ //
+ // If the HAL does not already own the display, then print an empty string.
+ // This guarantees that the file descriptor DisplayFile is valid.
+ //
+
+ if (!HalOwnsDisplay) {
+ HalDisplayString("");
+ }
+
+ //
+ // Build ANSI sequence to set the cursor position.
+ //
+
+ sprintf(SetCursorPositionString,"%c%d;%dH",CSI,CursorRow,CursorColumn);
+ ArcWrite(DisplayFile,SetCursorPositionString,strlen(SetCursorPositionString),&Count);
+
+ return;
+}
diff --git a/private/ntos/nthals/haldti/mips/jxebsup.c b/private/ntos/nthals/haldti/mips/jxebsup.c
new file mode 100644
index 000000000..eb764f0fd
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/jxebsup.c
@@ -0,0 +1,2376 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ ixhwsup.c
+
+Abstract:
+
+ This module contains the IoXxx routines for the NT I/O system that
+ are hardware dependent. Were these routines not hardware dependent,
+ they would reside in the iosubs.c module.
+
+Author:
+
+ Darryl E. Havens (darrylh) 11-Apr-1990
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "halp.h"
+#include "dtidef.h"
+#include "eisa.h"
+#include "bugcodes.h"
+
+//
+// Define the context structure for use by the interrupt routine.
+//
+
+typedef BOOLEAN (*PSECONDARY_DISPATCH)(
+ PVOID InterruptRoutine
+ );
+
+extern PVOID HalpEisaControlBase;
+
+//
+// Define save area for EISA adapter objects.
+//
+
+PADAPTER_OBJECT HalpEisaAdapter[8];
+
+UCHAR HalpEisaInterrupt1Mask;
+UCHAR HalpEisaInterrupt2Mask;
+UCHAR HalpEisaInterrupt1Level;
+UCHAR HalpEisaInterrupt2Level;
+
+VOID
+HalpCopyBufferMap(
+ IN PMDL Mdl,
+ IN PTRANSLATION_ENTRY TranslationEntry,
+ IN PVOID CurrentVa,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice,
+ IN ULONG noncachedAddress
+ );
+
+NTSTATUS
+HalAllocateAdapterChannel(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN PWAIT_CONTEXT_BLOCK Wcb,
+ IN ULONG NumberOfMapRegisters,
+ IN PDRIVER_CONTROL ExecutionRoutine
+ )
+/*++
+
+Routine Description:
+
+ This routine allocates the adapter channel specified by the adapter object.
+ This is accomplished by placing the device object of the driver that wants
+ to allocate the adapter on the adapter's queue. If the queue is already
+ "busy", then the adapter has already been allocated, so the device object
+ is simply placed onto the queue and waits until the adapter becomes free.
+
+ Once the adapter becomes free (or if it already is), then the driver's
+ execution routine is invoked.
+
+ Also, a number of map registers may be allocated to the driver by specifying
+ a non-zero value for NumberOfMapRegisters. Then the map register must be
+ allocated from the master adapter. Once there are a sufficient number of
+ map registers available, then the execution routine is called and the
+ base address of the allocated map registers in the adapter is also passed
+ to the driver's execution routine.
+
+Arguments:
+
+ AdapterObject - Pointer to the adapter control object to allocate to the
+ driver.
+
+ Wcb - Supplies a wait context block for saving the allocation parameters.
+ The DeviceObject, CurrentIrp and DeviceContext should be initalized.
+
+ NumberOfMapRegisters - The number of map registers that are to be allocated
+ from the channel, if any.
+
+ ExecutionRoutine - The address of the driver's execution routine that is
+ invoked once the adapter channel (and possibly map registers) have been
+ allocated.
+
+Return Value:
+
+ Returns STATUS_SUCESS unless too many map registers are requested.
+
+Notes:
+
+ Note that this routine MUST be invoked at DISPATCH_LEVEL or above.
+
+--*/
+{
+
+ PADAPTER_OBJECT MasterAdapter;
+ BOOLEAN Busy = FALSE;
+ IO_ALLOCATION_ACTION Action;
+ KIRQL Irql;
+ LONG MapRegisterNumber;
+
+ //
+ // Begin by obtaining a pointer to the master adapter associated with this
+ // request.
+ //
+
+ MasterAdapter = AdapterObject->MasterAdapter;
+
+ //
+ // Initialize the device object's wait context block in case this device
+ // must wait before being able to allocate the adapter.
+ //
+
+ Wcb->DeviceRoutine = ExecutionRoutine;
+ Wcb->NumberOfMapRegisters = NumberOfMapRegisters;
+
+ //
+ // Allocate the adapter object for this particular device. If the
+ // adapter cannot be allocated because it has already been allocated
+ // to another device, then return to the caller now; otherwise,
+ // continue.
+ //
+
+ if (!KeInsertDeviceQueue( &AdapterObject->ChannelWaitQueue,
+ &Wcb->WaitQueueEntry )) {
+
+ //
+ // Save the parameters in case there are not enough map registers.
+ //
+
+ AdapterObject->NumberOfMapRegisters = NumberOfMapRegisters;
+ AdapterObject->CurrentWcb = Wcb;
+
+ //
+ // The adapter was not busy so it has been allocated. Now check
+ // to see whether this driver wishes to allocate any map registers.
+ // Ensure that this adapter has enough total map registers
+ // to satisfy the request.
+ //
+
+ if (NumberOfMapRegisters != 0 && AdapterObject->NeedsMapRegisters) {
+
+ //
+ // Lock the map register bit map and the adapter queue in the
+ // master adapter object. The channel structure offset is used as
+ // a hint for the register search.
+ //
+
+ if (NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel) {
+ AdapterObject->NumberOfMapRegisters = 0;
+ IoFreeAdapterChannel(AdapterObject);
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ KeAcquireSpinLock( &MasterAdapter->SpinLock, &Irql );
+
+ MapRegisterNumber = -1;
+
+ if (IsListEmpty( &MasterAdapter->AdapterQueue)) {
+
+ MapRegisterNumber = RtlFindClearBitsAndSet(
+ MasterAdapter->MapRegisters,
+ NumberOfMapRegisters,
+ 0
+ );
+ }
+
+ if (MapRegisterNumber == -1) {
+
+ //
+ // There were not enough free map registers. Queue this request
+ // on the master adapter where is will wait until some registers
+ // are deallocated.
+ //
+
+ InsertTailList( &MasterAdapter->AdapterQueue,
+ &AdapterObject->AdapterQueue
+ );
+ Busy = 1;
+
+ } else {
+
+ //
+ // Calculate the map register base from the allocated map
+ // register and base of the master adapter object.
+ //
+
+ AdapterObject->MapRegisterBase = (PVOID)((PTRANSLATION_ENTRY)
+ MasterAdapter->MapRegisterBase + MapRegisterNumber);
+
+ //
+ // Set the no scatter/gather flag if scatter/gather not
+ // supported.
+ //
+
+ if (!AdapterObject->ScatterGather) {
+
+ AdapterObject->MapRegisterBase = (PVOID)
+ ((ULONG) AdapterObject->MapRegisterBase | NO_SCATTER_GATHER);
+
+ }
+ }
+
+ KeReleaseSpinLock( &MasterAdapter->SpinLock, Irql );
+
+ } else {
+
+ AdapterObject->MapRegisterBase = NULL;
+ AdapterObject->NumberOfMapRegisters = 0;
+ }
+
+ //
+ // If there were either enough map registers available or no map
+ // registers needed to be allocated, invoke the driver's execution
+ // routine now.
+ //
+
+ if (!Busy) {
+
+ AdapterObject->CurrentWcb = Wcb;
+ Action = 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.
+ NumberOfMapRegisters - Number of map registers requested and updated to
+ show actual number allocated.
+
+Return Value:
+
+ Returns STATUS_SUCESS if map registers allocated.
+
+--*/
+{
+ PADAPTER_OBJECT MasterAdapter;
+ ULONG MapRegisterNumber;
+
+ //
+ // Begin by obtaining a pointer to the master adapter associated with this
+ // request.
+ //
+
+ MasterAdapter = AdapterObject->MasterAdapter;
+
+ //
+ // Check to see whether this driver needs to allocate any map registers.
+ //
+
+ if (AdapterObject->NeedsMapRegisters) {
+
+ //
+ // Ensure that this adapter has enough total map registers to satisfy
+ // the request.
+ //
+
+ if (*NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel) {
+ AdapterObject->NumberOfMapRegisters = 0;
+ return NULL;
+ }
+
+ //
+ // Attempt to allocate the required number of map registers w/o
+ // affecting those registers that were allocated when the system
+ // crashed.
+ //
+
+ MapRegisterNumber = (ULONG)-1;
+
+ MapRegisterNumber = RtlFindClearBitsAndSet(
+ MasterAdapter->MapRegisters,
+ *NumberOfMapRegisters,
+ 0
+ );
+
+ if (MapRegisterNumber == (ULONG)-1) {
+
+ //
+ // Not enough free map registers were found, so they were busy
+ // being used by the system when it crashed. Force the appropriate
+ // number to be "allocated" at the base by simply overjamming the
+ // bits and return the base map register as the start.
+ //
+
+ RtlSetBits(
+ MasterAdapter->MapRegisters,
+ 0,
+ *NumberOfMapRegisters
+ );
+ MapRegisterNumber = 0;
+
+ }
+
+ //
+ // Calculate the map register base from the allocated map
+ // register and base of the master adapter object.
+ //
+
+ AdapterObject->MapRegisterBase = (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);
+ }
+
+ } else {
+
+ AdapterObject->MapRegisterBase = NULL;
+ AdapterObject->NumberOfMapRegisters = 0;
+ }
+
+ return AdapterObject->MapRegisterBase;
+}
+
+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;
+ UCHAR channelNumber;
+ ULONG controllerNumber;
+ DMA_EXTENDED_MODE extendedMode;
+ UCHAR adapterMode;
+ ULONG numberOfMapRegisters;
+ BOOLEAN useChannel;
+ BOOLEAN eisaSystem;
+ ULONG maximumLength;
+
+ eisaSystem = HalpBusType == MACHINE_TYPE_EISA ? TRUE : FALSE;
+
+ //
+ // 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;
+ }
+
+ //
+ // 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 (!eisaSystem &&
+ numberOfMapRegisters > HalpMapBufferSize / (PAGE_SIZE * 2)) {
+
+ numberOfMapRegisters = (HalpMapBufferSize / (PAGE_SIZE * 2));
+ }
+
+ //
+ // If the device is not a master then it only needs one map register
+ // and does scatter/Gather.
+ //
+
+ if (DeviceDescriptor->ScatterGather && !DeviceDescriptor->Master) {
+
+ numberOfMapRegisters = 1;
+ }
+ }
+
+ //
+ // Set the channel number number.
+ //
+
+ channelNumber = (UCHAR)(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 on
+ // 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 ) {
+
+ if (!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->ScatterGather = DeviceDescriptor->ScatterGather;
+ *NumberOfMapRegisters = adapterObject->MapRegistersPerChannel;
+
+ //
+ // 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 = channelNumber;
+
+ if (controllerNumber == 1) {
+
+ switch (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 (eisaSystem) {
+
+ //
+ // 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_REGISTER_UCHAR( adapterBaseVa, *((PUCHAR) &extendedMode));
+
+ } else if (!DeviceDescriptor->Master) {
+
+
+ switch (DeviceDescriptor->DmaWidth) {
+ case Width8Bits:
+
+ //
+ // The channel must use controller 1.
+ //
+
+ if (controllerNumber != 1) {
+ ObDereferenceObject( adapterObject );
+ return(NULL);
+ }
+
+ break;
+
+ case Width16Bits:
+
+ //
+ // The channel must use controller 2.
+ //
+
+ if (controllerNumber != 2) {
+ ObDereferenceObject( adapterObject );
+ return(NULL);
+ }
+
+ adapterObject->Width16Bits = TRUE;
+ break;
+
+ default:
+ ObDereferenceObject( adapterObject );
+ return(NULL);
+
+ }
+ }
+
+ //
+ // Initialize the adapter mode register value to the correct parameters,
+ // and save them in the adapter object.
+ //
+
+ adapterMode = 0;
+ ((PDMA_EISA_MODE) &adapterMode)->Channel = adapterObject->ChannelNumber;
+
+ adapterObject->MasterDevice = FALSE;
+
+ if (DeviceDescriptor->Master) {
+
+ adapterObject->MasterDevice = TRUE;
+
+ ((PDMA_EISA_MODE) &adapterMode)->RequestMode = CASCADE_REQUEST_MODE;
+
+ //
+ // Set the mode, and enable the request.
+ //
+
+ if (adapterObject->AdapterNumber == 1) {
+
+ //
+ // This request is for DMA controller 1
+ //
+
+ PDMA1_CONTROL dmaControl;
+
+ dmaControl = adapterObject->AdapterBaseVa;
+
+ WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode );
+
+ //
+ // Unmask the DMA channel.
+ //
+
+ WRITE_REGISTER_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber)
+ );
+
+ } else {
+
+ //
+ // This request is for DMA controller 1
+ //
+
+ PDMA2_CONTROL dmaControl;
+
+ dmaControl = adapterObject->AdapterBaseVa;
+
+ WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode );
+
+ //
+ // Unmask the DMA channel.
+ //
+
+ WRITE_REGISTER_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber)
+ );
+
+ }
+
+ } else if (DeviceDescriptor->DemandMode) {
+
+ ((PDMA_EISA_MODE) &adapterMode)->RequestMode = DEMAND_REQUEST_MODE;
+
+ } else {
+
+ ((PDMA_EISA_MODE) &adapterMode)->RequestMode = SINGLE_REQUEST_MODE;
+
+ }
+
+ if (DeviceDescriptor->AutoInitialize) {
+
+ ((PDMA_EISA_MODE) &adapterMode)->AutoInitialize = 1;
+
+ }
+
+ adapterObject->AdapterMode = adapterMode;
+
+ return(adapterObject);
+}
+
+PHYSICAL_ADDRESS
+IoMapTransfer(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN PMDL Mdl,
+ IN PVOID MapRegisterBase,
+ IN PVOID CurrentVa,
+ IN OUT PULONG Length,
+ IN BOOLEAN WriteToDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is invoked to set up the map registers in the DMA controller
+ to allow a transfer to or from a device.
+
+Arguments:
+
+ AdapterObject - Pointer to the adapter object representing the DMA
+ controller channel that has been allocated.
+
+ Mdl - Pointer to the MDL that describes the pages of memory that are
+ being read or written.
+
+ MapRegisterBase - The address of the base map register that has been
+ allocated to the device driver for use in mapping the transfer.
+
+ CurrentVa - Current virtual address in the buffer described by the MDL
+ that the transfer is being done to or from.
+
+ Length - Supplies the length of the transfer. This determines the
+ number of map registers that need to be written to map the transfer.
+ Returns the length of the transfer which was actually mapped.
+
+ WriteToDevice - Boolean value that indicates whether this is a write
+ to the device from memory (TRUE), or vice versa.
+
+Return Value:
+
+ Returns the logical address that should be used bus master controllers.
+
+--*/
+
+{
+ BOOLEAN useBuffer;
+ ULONG transferLength;
+ ULONG logicalAddress;
+ PHYSICAL_ADDRESS returnAddress;
+ ULONG index;
+ PULONG pageFrame;
+ PUCHAR bytePointer;
+ UCHAR adapterMode;
+ UCHAR dataByte;
+ PTRANSLATION_ENTRY translationEntry;
+ ULONG pageOffset;
+ KIRQL Irql;
+ ULONG noncachedAddress;
+ ULONG partialLength;
+ ULONG temp;
+
+ pageOffset = BYTE_OFFSET(CurrentVa);
+
+ //
+ // Calculate how much of the transfer is contiguous.
+ //
+
+ transferLength = PAGE_SIZE - pageOffset;
+ pageFrame = (PULONG)(Mdl+1);
+ pageFrame += ((ULONG) CurrentVa - (ULONG) Mdl->StartVa) >> PAGE_SHIFT;
+ logicalAddress = ((*pageFrame << PAGE_SHIFT) + pageOffset) & 0x03ffffff;
+
+ //
+ // If the buffer is contigous and does not cross a 64 K bountry then
+ // just extend the buffer. The 64 K bountry restriction does not apply
+ // to Eisa systems.
+ //
+
+ if (HalpBusType == MACHINE_TYPE_EISA) {
+
+ while( transferLength < *Length ){
+
+ if (*pageFrame + 1 != *(pageFrame + 1)) {
+ break;
+ }
+
+ transferLength += PAGE_SIZE;
+ pageFrame++;
+
+ }
+
+ } else {
+
+ while( transferLength < *Length ){
+
+ if (*pageFrame + 1 != *(pageFrame + 1) ||
+ (*pageFrame & ~0x0f) != (*(pageFrame + 1) & ~0x0f)) {
+ break;
+ }
+
+ transferLength += PAGE_SIZE;
+ pageFrame++;
+ }
+ }
+
+ //
+ // Limit the transferLength to the requested Length.
+ //
+
+ transferLength = transferLength > *Length ? *Length : transferLength;
+
+ //
+ // Determine if the data transfer needs to use the map buffer.
+ //
+
+ if (MapRegisterBase != NULL &&
+ !( ((*pageFrame<<PAGE_SHIFT) & 0x03ffffff) >= HalpMapBufferPhysicalAddress.LowPart &&
+ ((*pageFrame<<PAGE_SHIFT) & 0x03ffffff) < (HalpMapBufferPhysicalAddress.LowPart + HalpMapBufferSize))) {
+
+ //
+ // Strip no scatter/gather flag.
+ //
+
+ translationEntry = (PTRANSLATION_ENTRY) ((ULONG) MapRegisterBase & ~NO_SCATTER_GATHER);
+
+ if ((ULONG) MapRegisterBase & NO_SCATTER_GATHER
+ && transferLength < *Length) {
+
+ logicalAddress = translationEntry->PhysicalAddress + pageOffset;
+ translationEntry->Index = COPY_BUFFER;
+ index = 0;
+ transferLength = *Length;
+ useBuffer = TRUE;
+
+ } else {
+
+ //
+ // If there are map registers, then update the index to indicate
+ // how many have been used.
+ //
+
+ useBuffer = FALSE;
+ index = translationEntry->Index;
+ translationEntry->Index += ADDRESS_AND_SIZE_TO_SPAN_PAGES(
+ CurrentVa,
+ transferLength
+ );
+ }
+
+ //
+ // It must require memory to be at less than 16 MB. If the
+ // logical address is greater than 16MB then map registers must be used
+ //
+
+
+// Make IoMapTransfer() assume that all transfers are above 16 MB and have
+// to be mapped through the map buffer.
+
+// if (logicalAddress+transferLength >= MAXIMUM_PHYSICAL_ADDRESS) {
+
+ logicalAddress = (translationEntry + index)->PhysicalAddress +
+ pageOffset;
+ useBuffer = TRUE;
+
+ if ((ULONG) MapRegisterBase & NO_SCATTER_GATHER) {
+
+ translationEntry->Index = COPY_BUFFER;
+ index = 0;
+
+ }
+
+// }
+
+ //
+ // Copy the data if necessary.
+ //
+
+ if (useBuffer && WriteToDevice) {
+
+// HalpCopyBufferMap(
+// Mdl,
+// translationEntry + index,
+// CurrentVa,
+// *Length,
+// WriteToDevice,
+// noncachedAddress
+// );
+
+ temp = transferLength;
+
+ transferLength = PAGE_SIZE - BYTE_OFFSET(CurrentVa);
+ partialLength = transferLength;
+ pageFrame = (PULONG)(Mdl+1);
+ pageFrame += ((ULONG) CurrentVa - (ULONG) Mdl->StartVa) >> PAGE_SHIFT;
+
+ while( transferLength <= *Length ) {
+
+ noncachedAddress = KSEG1_BASE | ((*pageFrame << PAGE_SHIFT) + BYTE_OFFSET(CurrentVa));
+
+ HalpCopyBufferMap(
+ Mdl,
+ translationEntry + index,
+ CurrentVa,
+ partialLength,
+ WriteToDevice,
+ noncachedAddress
+ );
+
+ (PCCHAR) CurrentVa += partialLength;
+ partialLength = PAGE_SIZE;
+
+ //
+ // Note that transferLength indicates the amount which will be
+ // transfered after the next loop; thus, it is updated with the
+ // new partial length.
+ //
+
+ transferLength += partialLength;
+ pageFrame++;
+ translationEntry++;
+
+ }
+
+ //
+ // Process the any remaining residue.
+ //
+
+ partialLength = *Length - transferLength + partialLength;
+
+ if (partialLength) {
+
+ noncachedAddress = KSEG1_BASE | ((*pageFrame << PAGE_SHIFT) + BYTE_OFFSET(CurrentVa));
+
+ HalpCopyBufferMap(
+ Mdl,
+ translationEntry + index,
+ CurrentVa,
+ partialLength,
+ WriteToDevice,
+ noncachedAddress
+ );
+
+ }
+
+ transferLength = temp;
+
+ }
+ }
+
+ //
+ // Return the length.
+ //
+
+ *Length = transferLength;
+
+ //
+ // We only support 32 bits, but the return is 64. Just
+ // zero extend
+ //
+
+ returnAddress.LowPart = logicalAddress;
+ returnAddress.HighPart = 0;
+
+ //
+ // If no adapter was specificed then there is no more work to do so
+ // return.
+ //
+
+ if (AdapterObject == NULL || AdapterObject->MasterDevice) {
+
+ return(returnAddress);
+ }
+
+ //
+ // Determine the mode based on the transfer direction.
+ //
+
+ adapterMode = AdapterObject->AdapterMode;
+ ((PDMA_EISA_MODE) &adapterMode)->TransferType = (UCHAR) (WriteToDevice ?
+ WRITE_TRANSFER : READ_TRANSFER);
+
+ bytePointer = (PUCHAR) &logicalAddress;
+
+ if (AdapterObject->Width16Bits) {
+
+ //
+ // If this is a 16 bit transfer then adjust the length and the address
+ // for the 16 bit DMA mode.
+ //
+
+ transferLength >>= 1;
+
+ //
+ // In 16 bit DMA mode the low 16 bits are shifted right one and the
+ // page register value is unchanged. So save the page register value
+ // and shift the logical address then restore the page value.
+ //
+
+ dataByte = bytePointer[2];
+ logicalAddress >>= 1;
+ bytePointer[2] = dataByte;
+
+ }
+
+
+ //
+ // grab the spinlock for the system DMA controller
+ //
+
+ KeAcquireSpinLock( &AdapterObject->MasterAdapter->SpinLock, &Irql );
+
+ //
+ // Determine the controller number based on the Adapter number.
+ //
+
+ if (AdapterObject->AdapterNumber == 1) {
+
+ //
+ // This request is for DMA controller 1
+ //
+
+ PDMA1_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_REGISTER_UCHAR( &dmaControl->ClearBytePointer, 0 );
+
+ WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode );
+
+ WRITE_REGISTER_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseAddress,
+ bytePointer[0]
+ );
+
+ WRITE_REGISTER_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseAddress,
+ bytePointer[1]
+ );
+
+ WRITE_REGISTER_UCHAR(
+ ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageLowPort) +
+ (ULONG)AdapterObject->PagePort,
+ bytePointer[2]
+ );
+
+ if (HalpBusType == MACHINE_TYPE_EISA) {
+
+ //
+ // Write the high page register with zero value. This enable a special mode
+ // which allows ties the page register and base count into a single 24 bit
+ // address register.
+ //
+
+ WRITE_REGISTER_UCHAR(
+ ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort) +
+ (ULONG)AdapterObject->PagePort,
+ 0
+ );
+ }
+
+ //
+ // Notify DMA chip of the length to transfer.
+ //
+
+ WRITE_REGISTER_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount,
+ (UCHAR) ((transferLength - 1) & 0xff)
+ );
+
+ WRITE_REGISTER_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount,
+ (UCHAR) ((transferLength - 1) >> 8)
+ );
+
+
+ //
+ // Set the DMA chip to read or write mode; and unmask it.
+ //
+
+ WRITE_REGISTER_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber)
+ );
+
+ } else {
+
+ //
+ // This request is for DMA controller 2
+ //
+
+ PDMA2_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_REGISTER_UCHAR( &dmaControl->ClearBytePointer, 0 );
+
+ WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode );
+
+ WRITE_REGISTER_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseAddress,
+ bytePointer[0]
+ );
+
+ WRITE_REGISTER_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseAddress,
+ bytePointer[1]
+ );
+
+ WRITE_REGISTER_UCHAR(
+ ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageLowPort) +
+ (ULONG)AdapterObject->PagePort,
+ bytePointer[2]
+ );
+
+ if (HalpBusType == MACHINE_TYPE_EISA) {
+
+ //
+ // Write the high page register with zero value. This enable a special mode
+ // which allows ties the page register and base count into a single 24 bit
+ // address register.
+ //
+
+ WRITE_REGISTER_UCHAR(
+ ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort) +
+ (ULONG)AdapterObject->PagePort,
+ 0
+ );
+ }
+
+ //
+ // Notify DMA chip of the length to transfer.
+ //
+
+ WRITE_REGISTER_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount,
+ (UCHAR) ((transferLength - 1) & 0xff)
+ );
+
+ WRITE_REGISTER_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount,
+ (UCHAR) ((transferLength - 1) >> 8)
+ );
+
+
+ //
+ // Set the DMA chip to read or write mode; and unmask it.
+ //
+
+ WRITE_REGISTER_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber)
+ );
+
+ }
+ KeReleaseSpinLock (&AdapterObject->MasterAdapter->SpinLock, Irql);
+
+ return(returnAddress);
+}
+
+BOOLEAN
+IoFlushAdapterBuffers(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN PMDL Mdl,
+ IN PVOID MapRegisterBase,
+ IN PVOID CurrentVa,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine flushes the DMA adapter object buffers. For the Jazz system
+ its clears the enable flag which aborts the dma.
+
+Arguments:
+
+ AdapterObject - Pointer to the adapter object representing the DMA
+ controller channel.
+
+ Mdl - A pointer to a Memory Descriptor List (MDL) that maps the locked-down
+ buffer to/from which the I/O occured.
+
+ MapRegisterBase - A pointer to the base of the map registers in the adapter
+ or DMA controller.
+
+ CurrentVa - The current virtual address in the buffer described the the Mdl
+ where the I/O operation occurred.
+
+ Length - Supplies the length of the transfer.
+
+ WriteToDevice - Supplies a BOOLEAN value that indicates the direction of
+ the data transfer was to the device.
+
+Return Value:
+
+ TRUE - No errors are detected so the transfer must succeed.
+
+--*/
+
+{
+ PTRANSLATION_ENTRY translationEntry;
+ PULONG pageFrame;
+ ULONG transferLength;
+ ULONG partialLength;
+ BOOLEAN masterDevice;
+ ULONG logicalAddress;
+ ULONG noncachedAddress;
+
+ ULONG PagesAbove16MB;
+ ULONG PagesBelow16MB;
+
+ pageFrame = (PULONG)(Mdl+1);
+ pageFrame += ((ULONG) CurrentVa - (ULONG) Mdl->StartVa) >> PAGE_SHIFT;
+
+ masterDevice = AdapterObject == NULL || AdapterObject->MasterDevice ?
+ TRUE : FALSE;
+
+ //
+ // If this is a slave device, then stop the DMA controller.
+ //
+
+ if (!masterDevice) {
+
+ //
+ // Mask the DMA request line so that DMA requests cannot occur.
+ //
+
+ if (AdapterObject->AdapterNumber == 1) {
+
+ //
+ // This request is for DMA controller 1
+ //
+
+ PDMA1_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_REGISTER_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_SETMASK | AdapterObject->ChannelNumber)
+ );
+
+ } else {
+
+ //
+ // This request is for DMA controller 2
+ //
+
+ PDMA2_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_REGISTER_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_SETMASK | AdapterObject->ChannelNumber)
+ );
+
+ }
+
+ }
+
+ if (MapRegisterBase == NULL ||
+ ( ((*pageFrame<<PAGE_SHIFT) & 0x03ffffff) >= HalpMapBufferPhysicalAddress.LowPart &&
+ ((*pageFrame<<PAGE_SHIFT) & 0x03ffffff) < (HalpMapBufferPhysicalAddress.LowPart + HalpMapBufferSize))) {
+ return(TRUE);
+ }
+
+ //
+ // Determine if the data needs to be copied to the orginal buffer.
+ // This only occurs if the data tranfer is from the device, the
+ // MapReisterBase is not NULL and the transfer spans a page.
+ //
+
+ if (!WriteToDevice) {
+
+ //
+ // Strip no scatter/gather flag.
+ //
+
+ translationEntry = (PTRANSLATION_ENTRY) ((ULONG) MapRegisterBase & ~NO_SCATTER_GATHER);
+
+ //
+ // If this is not a master device, then just transfer the buffer.
+ //
+
+ if ((ULONG) MapRegisterBase & NO_SCATTER_GATHER) {
+
+ if (translationEntry->Index == COPY_BUFFER) {
+
+ if (!masterDevice) {
+
+ //
+ // Copy only the bytes that have actually been transfered.
+ //
+
+ Length -= HalReadDmaCounter(AdapterObject);
+
+ }
+
+ //
+ // The adapter does not support scatter/gather copy the buffer.
+ //
+
+ transferLength = PAGE_SIZE - BYTE_OFFSET(CurrentVa);
+ partialLength = transferLength;
+ pageFrame = (PULONG)(Mdl+1);
+ pageFrame += ((ULONG) CurrentVa - (ULONG) Mdl->StartVa) >> PAGE_SHIFT;
+
+ while( transferLength <= Length ){
+
+ logicalAddress = (*pageFrame << PAGE_SHIFT) + BYTE_OFFSET(CurrentVa);
+ noncachedAddress = KSEG1_BASE | logicalAddress;
+
+ HalpCopyBufferMap(
+ Mdl,
+ translationEntry,
+ CurrentVa,
+ partialLength,
+ WriteToDevice,
+ noncachedAddress
+ );
+
+ (PCCHAR) CurrentVa += partialLength;
+ partialLength = PAGE_SIZE;
+
+ //
+ // Note that transferLength indicates the amount which will be
+ // transfered after the next loop; thus, it is updated with the
+ // new partial length.
+ //
+
+ transferLength += partialLength;
+ pageFrame++;
+ translationEntry++;
+ }
+
+ //
+ // Process the any remaining residue.
+ //
+
+ partialLength = Length - transferLength + partialLength;
+
+ if (partialLength) {
+
+ logicalAddress = (*pageFrame << PAGE_SHIFT) + BYTE_OFFSET(CurrentVa);
+ noncachedAddress = KSEG1_BASE | logicalAddress;
+
+ HalpCopyBufferMap(
+ Mdl,
+ translationEntry,
+ CurrentVa,
+ partialLength,
+ WriteToDevice,
+ noncachedAddress
+ );
+
+ }
+ }
+
+ } else {
+
+ //
+ // Cycle through the pages of the transfer to determine if there
+ // are any which need to be copied back.
+ //
+
+ transferLength = PAGE_SIZE - BYTE_OFFSET(CurrentVa);
+ partialLength = transferLength;
+ pageFrame = (PULONG)(Mdl+1);
+ pageFrame += ((ULONG) CurrentVa - (ULONG) Mdl->StartVa) >> PAGE_SHIFT;
+
+ PagesBelow16MB = 0;
+ PagesAbove16MB = 0;
+
+ while( transferLength <= Length ){
+
+// Make IoFlushAdapterBuffers assume that all transfers are above 16MB
+// and have to be mapped through the map buffer.
+
+// if (*pageFrame >= BYTES_TO_PAGES(MAXIMUM_PHYSICAL_ADDRESS)) {
+
+ logicalAddress = (*pageFrame << PAGE_SHIFT) + BYTE_OFFSET(CurrentVa);
+ noncachedAddress = KSEG1_BASE | logicalAddress;
+
+ HalpCopyBufferMap(
+ Mdl,
+ translationEntry,
+ CurrentVa,
+ partialLength,
+ WriteToDevice,
+ noncachedAddress
+ );
+
+ PagesAbove16MB++;
+
+// }
+//
+// else {
+//
+// PagesBelow16MB++;
+//
+// }
+
+ (PCCHAR) CurrentVa += partialLength;
+ partialLength = PAGE_SIZE;
+
+ //
+ // Note that transferLength indicates the amount which will be
+ // transfered after the next loop; thus, it is updated with the
+ // new partial length.
+ //
+
+ transferLength += partialLength;
+ pageFrame++;
+ translationEntry++;
+ }
+
+ //
+ // Process the any remaining residue.
+ //
+
+ partialLength = Length - transferLength + partialLength;
+
+// Make IoFlushAdapterBuffer assume that all transfers are above 16MB and
+// have to be mapped through the map buffer.
+
+// if (partialLength && *pageFrame >= BYTES_TO_PAGES(MAXIMUM_PHYSICAL_ADDRESS)) {
+
+ if (partialLength) {
+
+// if (*pageFrame >= BYTES_TO_PAGES(MAXIMUM_PHYSICAL_ADDRESS)) {
+
+ logicalAddress = (*pageFrame << PAGE_SHIFT) + BYTE_OFFSET(CurrentVa);
+ noncachedAddress = KSEG1_BASE | logicalAddress;
+
+ HalpCopyBufferMap(
+ Mdl,
+ translationEntry,
+ CurrentVa,
+ partialLength,
+ WriteToDevice,
+ noncachedAddress
+ );
+
+ PagesAbove16MB++;
+
+// }
+//
+// else {
+//
+// PagesBelow16MB++;
+//
+// }
+ }
+
+ }
+ }
+
+ //
+ // Strip no scatter/gather flag.
+ //
+
+ translationEntry = (PTRANSLATION_ENTRY) ((ULONG) MapRegisterBase & ~NO_SCATTER_GATHER);
+
+ //
+ // Clear index in map register.
+ //
+
+ translationEntry->Index = 0;
+
+ return TRUE;
+}
+
+ULONG
+HalReadDmaCounter(
+ IN PADAPTER_OBJECT AdapterObject
+ )
+/*++
+
+Routine Description:
+
+ This function reads the DMA counter and returns the number of bytes left
+ to be transfered.
+
+Arguments:
+
+ AdapterObject - Supplies a pointer to the adapter object to be read.
+
+Return Value:
+
+ Returns the number of bytes still be be transfered.
+
+--*/
+
+{
+ ULONG i;
+ ULONG saveEnable;
+ ULONG count;
+ ULONG high;
+
+ if (AdapterObject->PagePort) {
+
+ //
+ // 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;
+
+ //
+ // Initialize count to a value which will not match.
+ //
+
+ count = 0xFFFF00;
+
+ //
+ // Loop until the same high byte is read twice.
+ //
+
+ do {
+
+ high = count;
+
+ WRITE_REGISTER_UCHAR( &dmaControl->ClearBytePointer, 0 );
+
+ //
+ // Read the current DMA count.
+ //
+
+ count = READ_REGISTER_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount
+ );
+
+ count |= READ_REGISTER_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount
+ ) << 8;
+
+ } while ((count & 0xFFFF00) != (high & 0xFFFF00));
+
+ } else {
+
+ //
+ // This request is for DMA controller 2
+ //
+
+ PDMA2_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ //
+ // Initialize count to a value which will not match.
+ //
+
+ count = 0xFFFF00;
+
+ //
+ // Loop until the same high byte is read twice.
+ //
+
+ do {
+
+ high = count;
+
+ WRITE_REGISTER_UCHAR( &dmaControl->ClearBytePointer, 0 );
+
+ //
+ // Read the current DMA count.
+ //
+
+ count = READ_REGISTER_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount
+ );
+
+ count |= READ_REGISTER_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount
+ ) << 8;
+
+ } while ((count & 0xFFFF00) != (high & 0xFFFF00));
+
+ }
+
+ //
+ // The DMA counter has a bias of one and can only be 16 bit long.
+ //
+
+ count = (count + 1) & 0xFFFF;
+
+ }
+
+ return(count);
+}
+
+VOID
+HalpEnableEisaInterrupt(
+ IN ULONG Vector,
+ IN KINTERRUPT_MODE InterruptMode
+ )
+
+/*++
+
+Routine Description:
+
+ This function enables the EISA bus specified EISA bus interrupt and sets
+ the level/edge register to the requested value.
+
+Arguments:
+
+ Vector - Supplies the vector of the ESIA interrupt that is enabled.
+
+ InterruptMode - Supplies the mode of the interrupt; LevelSensitive or
+ Latched.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Calculate the EISA interrupt vector.
+ //
+
+ Vector -= EISA_VECTORS;
+
+ //
+ // Determine if this vector is for interrupt controller 1 or 2.
+ //
+
+ if (Vector & 0x08) {
+
+ //
+ // The interrupt is in controller 2.
+ //
+
+ Vector &= 0x7;
+
+ HalpEisaInterrupt2Mask &= (UCHAR) ~(1 << Vector);
+ WRITE_REGISTER_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
+ HalpEisaInterrupt2Mask
+ );
+
+ //
+ // Set the level/edge control register.
+ //
+
+ if (InterruptMode == LevelSensitive) {
+
+ HalpEisaInterrupt2Level |= (UCHAR) (1 << Vector);
+
+ } else {
+
+ HalpEisaInterrupt2Level &= (UCHAR) ~(1 << Vector);
+
+ }
+
+ WRITE_REGISTER_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2EdgeLevel,
+ HalpEisaInterrupt2Level
+ );
+
+ } else {
+
+ //
+ // The interrupt is in controller 1.
+ //
+
+ Vector &= 0x7;
+
+ HalpEisaInterrupt1Mask &= (UCHAR) ~(1 << Vector);
+ WRITE_REGISTER_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ HalpEisaInterrupt1Mask
+ );
+
+ //
+ // Set the level/edge control register.
+ //
+
+ if (InterruptMode == LevelSensitive) {
+
+ HalpEisaInterrupt1Level |= (UCHAR) (1 << Vector);
+
+ } else {
+
+ HalpEisaInterrupt1Level &= (UCHAR) ~(1 << Vector);
+
+ }
+
+ WRITE_REGISTER_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1EdgeLevel,
+ HalpEisaInterrupt1Level
+ );
+ }
+
+}
+
+VOID
+HalpDisableEisaInterrupt(
+ IN ULONG Vector
+ )
+
+/*++
+
+Routine Description:
+
+ This function Disables the EISA bus specified EISA bus interrupt.
+
+Arguments:
+
+ Vector - Supplies the vector of the ESIA interrupt that is Disabled.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Calculate the EISA interrupt vector.
+ //
+
+ Vector -= EISA_VECTORS;
+
+ //
+ // Determine if this vector is for interrupt controller 1 or 2.
+ //
+
+ if (Vector & 0x08) {
+
+ //
+ // The interrupt is in controller 2.
+ //
+
+ Vector &= 0x7;
+
+ HalpEisaInterrupt2Mask |= (UCHAR) 1 << Vector;
+ WRITE_REGISTER_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
+ HalpEisaInterrupt2Mask
+ );
+
+ } else {
+
+ //
+ // The interrupt is in controller 1.
+ //
+
+ Vector &= 0x7;
+
+ HalpEisaInterrupt1Mask |= (ULONG) 1 << Vector;
+ WRITE_REGISTER_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ HalpEisaInterrupt1Mask
+ );
+
+ }
+
+}
+
+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;
+
+// //
+// // Initialize the EISA NMI interrupt.
+// //
+//
+//
+// PCR->InterruptRoutine[EISA_NMI_LEVEL] = HalHandleNMI;
+//
+// //
+// // Clear the Eisa NMI disable bit. This bit is the high order of the
+// // NMI enable register.
+// //
+//
+// DataByte = 0;
+// //
+// // TEMPTEMP Disable the NMI because this is causing machines in the build
+// // lab to fail.
+// //
+// DataByte = 0x80;
+//
+// WRITE_REGISTER_UCHAR(
+// &((PEISA_CONTROL) HalpEisaControlBase)->NmiEnable,
+// DataByte
+// );
+
+ //
+ // Initialize the EISA interrupt dispatcher for ArcStation I/O interrupts.
+ //
+
+
+ PCR->InterruptRoutine[EISA_DEVICE_LEVEL] = (PKINTERRUPT_ROUTINE)HalpEisaDispatch;
+
+ //
+ // 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_REGISTER_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
+ DataByte
+ );
+
+ WRITE_REGISTER_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0,
+ DataByte
+ );
+
+ //
+ // The second intitialization control word sets the iterrupt vector to
+ // 0-15.
+ //
+
+ DataByte = 0;
+
+ WRITE_REGISTER_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ DataByte
+ );
+
+ DataByte = 0x08;
+
+ WRITE_REGISTER_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_REGISTER_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ DataByte
+ );
+
+ DataByte = SLAVE_IRQL_LEVEL;
+
+ WRITE_REGISTER_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_REGISTER_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ DataByte
+ );
+
+ WRITE_REGISTER_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
+ DataByte
+ );
+
+
+ //
+ // Disable all of the interrupts except the slave.
+ //
+
+ HalpEisaInterrupt1Mask = (UCHAR)(~(1 << SLAVE_IRQL_LEVEL));
+
+ WRITE_REGISTER_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ HalpEisaInterrupt1Mask
+ );
+
+ HalpEisaInterrupt2Mask = 0xFF;
+
+ WRITE_REGISTER_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;
+
+ //
+ // Initialize the DMA mode registers to a default value.
+ // Disable all of the DMA channels except channel 4 which is that
+ // cascade of channels 0-3.
+ //
+
+ WRITE_REGISTER_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Dma1BasePort.AllMask,
+ 0x0F
+ );
+
+ WRITE_REGISTER_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.
+
+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;
+ PULONG dispatchCode;
+ PKINTERRUPT interruptObject;
+ USHORT PCRInOffset;
+ BOOLEAN returnValue;
+
+ //
+ // Send a POLL Command to Interrupt Controller 1
+ //
+
+ WRITE_REGISTER_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
+ 0x0c
+ );
+
+ //
+ // Read the interrupt vector
+ //
+
+ interruptVector =
+ READ_REGISTER_UCHAR(&((PEISA_CONTROL)HalpEisaControlBase)->Interrupt1ControlPort0);
+
+ //
+ // See if there is really an interrupt present
+ //
+
+ if (interruptVector & 0x80) {
+
+ //
+ // Strip off the all the bits except for the interrupt vector
+ //
+
+ interruptVector &= 0x07;
+
+ //
+ // See if this is an interrupt on IRQ2 which is cascaded to the
+ // other interrupt controller
+ //
+
+ if (interruptVector != 0x02) {
+
+ //
+ // This interrupt is on the first interrupt controller
+ //
+
+ PCRInOffset = interruptVector + EISA_VECTORS;
+
+ //
+ // Dispatch to the secondary interrupt service routine.
+ //
+
+ //
+ // The interrupt vector for CLOCK2_LEVEL is directly connected by the HAL.
+ // If the interrupt is on CLOCK2_LEVEL then vector to the address stored
+ // in the PCR. Otherwise, bypass the thunk code in the interrupt object
+ // whose address is stored in the PCR.
+ //
+
+ if (PCRInOffset == CLOCK2_LEVEL) {
+
+ returnValue =
+ ((PSECONDARY_DISPATCH)PCR->InterruptRoutine[PCRInOffset])
+ (PCR->InterruptRoutine[PCRInOffset]);
+
+ } else {
+
+ dispatchCode = (PULONG)(PCR->InterruptRoutine[PCRInOffset]);
+ interruptObject = CONTAINING_RECORD(dispatchCode,
+ KINTERRUPT,
+ DispatchCode);
+
+ returnValue =
+ ((PSECONDARY_DISPATCH)interruptObject->DispatchAddress)
+ (interruptObject);
+
+ }
+
+ //
+ // Clear the interrupt from Interrupt Controller 1
+ //
+
+ WRITE_REGISTER_UCHAR(
+ &((PEISA_CONTROL)HalpEisaControlBase)->Interrupt1ControlPort0,
+ NONSPECIFIC_END_OF_INTERRUPT
+ );
+
+ return returnValue;
+
+ } else {
+
+ //
+ // This interrupt is on the second interrupt controller
+ //
+
+ //
+ // Send a POLL Command to Interrupt Controller 2
+ //
+
+ WRITE_REGISTER_UCHAR(
+ &((PEISA_CONTROL)HalpEisaControlBase)->Interrupt2ControlPort0,
+ 0x0c
+ );
+
+ //
+ // Read the interrupt vector
+ //
+
+ interruptVector = READ_REGISTER_UCHAR(
+ &((PEISA_CONTROL)HalpEisaControlBase)->Interrupt2ControlPort0);
+
+ //
+ // See if there is really an interrupt present
+ //
+
+ if (interruptVector & 0x80) {
+
+ //
+ // Strip off the all the bits except for the interrupt vector
+ //
+
+ interruptVector &= 0x07;
+
+ PCRInOffset = interruptVector + 8 + EISA_VECTORS;
+
+ //
+ // Dispatch to the secondary interrupt service routine.
+ //
+
+ dispatchCode = (PULONG)(PCR->InterruptRoutine[PCRInOffset]);
+ interruptObject = CONTAINING_RECORD(dispatchCode,
+ KINTERRUPT,
+ DispatchCode);
+
+ returnValue =
+ ((PSECONDARY_DISPATCH)interruptObject->DispatchAddress)
+ (interruptObject);
+
+
+ //
+ // Clear the interrupt from Interrupt Controller 2
+ //
+
+ WRITE_REGISTER_UCHAR(
+ &((PEISA_CONTROL)HalpEisaControlBase)->Interrupt2ControlPort0,
+ NONSPECIFIC_END_OF_INTERRUPT
+ );
+
+ //
+ // Clear the interrupt from Interrupt Controller 1
+ //
+
+ WRITE_REGISTER_UCHAR(
+ &((PEISA_CONTROL)HalpEisaControlBase)->Interrupt1ControlPort0,
+ NONSPECIFIC_END_OF_INTERRUPT
+ );
+
+ return returnValue;
+
+ }
+ }
+ }
+}
diff --git a/private/ntos/nthals/haldti/mips/jxenvirv.c b/private/ntos/nthals/haldti/mips/jxenvirv.c
new file mode 100644
index 000000000..3d69ac268
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/jxenvirv.c
@@ -0,0 +1,98 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ jxenvirv.c
+
+Abstract:
+
+ This module implements the HAL get and set environment variable routines
+ for a MIPS system.
+
+Author:
+
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "arccodes.h"
+#include "string.h"
+
+ARC_STATUS
+HalGetEnvironmentVariable (
+ IN PCHAR Variable,
+ IN USHORT Length,
+ OUT PCHAR Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ This function locates an environment variable and returns its value.
+
+Arguments:
+
+ Variable - Supplies a pointer to a zero terminated environment variable
+ name.
+
+ Length - Supplies the length of the value buffer in bytes.
+
+ Buffer - Supplies a pointer to a buffer that receives the variable value.
+
+Return Value:
+
+ ESUCCESS is returned if the enviroment variable is located. Otherwise,
+ ENOENT is returned.
+
+--*/
+
+{
+ CHAR *Value;
+
+ Value = ArcGetEnvironmentVariable(Variable);
+ if (Value==NULL)
+ return(ENOENT);
+ if (strlen(Value)>Length)
+ return(ENOENT);
+ strcpy(Buffer,Value);
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+HalSetEnvironmentVariable (
+ IN PCHAR Variable,
+ IN PCHAR Value
+ )
+
+/*++
+
+Routine Description:
+
+ This function creates an environment variable with the specified value.
+
+Arguments:
+
+ Variable - Supplies a pointer to an environment variable name.
+
+ Value - Supplies a pointer to the environment variable value.
+
+Return Value:
+
+ ESUCCESS is returned if the environment variable is created. Otherwise,
+ ENOMEM is returned.
+
+--*/
+
+{
+ return(ArcSetEnvironmentVariable(Variable,Value));
+}
diff --git a/private/ntos/nthals/haldti/mips/jxhalp.h b/private/ntos/nthals/haldti/mips/jxhalp.h
new file mode 100644
index 000000000..42d5cdf9a
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/jxhalp.h
@@ -0,0 +1,105 @@
+/*++ BUILD Version: 0001 // Increment this if a change has global effects
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ jxhalp.h
+
+Abstract:
+
+ This header file defines the private Hardware Architecture Layer (HAL)
+ Jazz specific interfaces, defines and structures.
+
+Author:
+
+ Jeff Havens (jhavens) 20-Jun-91
+
+
+Revision History:
+
+--*/
+
+#ifndef _JXHALP_
+#define _JXHALP_
+
+
+//
+// Define global data used to locate the EISA control space and the realtime
+// clock registers.
+//
+
+extern PVOID HalpEisaControlBase;
+extern PVOID HalpEisaMemoryBase;
+extern PVOID HalpRealTimeClockBase;
+
+//
+// Define adapter object structure.
+//
+
+typedef struct _ADAPTER_OBJECT {
+ CSHORT Type;
+ CSHORT Size;
+ struct _ADAPTER_OBJECT *MasterAdapter;
+ ULONG MapRegistersPerChannel;
+ PVOID AdapterBaseVa;
+ PVOID MapRegisterBase;
+ ULONG NumberOfMapRegisters;
+ ULONG CommittedMapRegisters;
+ struct _WAIT_CONTEXT_BLOCK *CurrentWcb;
+ KDEVICE_QUEUE ChannelWaitQueue;
+ PKDEVICE_QUEUE RegisterWaitQueue;
+ LIST_ENTRY AdapterQueue;
+ KSPIN_LOCK SpinLock;
+ PRTL_BITMAP MapRegisters;
+ PUCHAR PagePort;
+ UCHAR ChannelNumber;
+ UCHAR AdapterNumber;
+ USHORT DmaPortAddress;
+ UCHAR AdapterMode;
+ BOOLEAN NeedsMapRegisters;
+ BOOLEAN MasterDevice;
+ BOOLEAN Width16Bits;
+ BOOLEAN ScatterGather;
+} ADAPTER_OBJECT;
+
+//
+// Define function prototypes.
+//
+
+PADAPTER_OBJECT
+HalpAllocateEisaAdapter(
+ IN PDEVICE_DESCRIPTION DeviceDescription
+ );
+
+BOOLEAN
+HalpCreateEisaStructures(
+ VOID
+ );
+
+VOID
+HalpDisableEisaInterrupt(
+ IN ULONG Vector
+ );
+
+BOOLEAN
+HalpEisaDispatch(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext
+ );
+
+VOID
+HalpEisaMapTransfer(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN ULONG Offset,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ );
+
+VOID
+HalpEnableEisaInterrupt(
+ IN ULONG Vector,
+ IN KINTERRUPT_MODE InterruptMode
+ );
+
+#endif // _JXHALP_
diff --git a/private/ntos/nthals/haldti/mips/jxhwsup.c b/private/ntos/nthals/haldti/mips/jxhwsup.c
new file mode 100644
index 000000000..b36595764
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/jxhwsup.c
@@ -0,0 +1,2024 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ixphwsup.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:
+
+ Darryl E. Havens (darrylh) 11-Apr-1990
+
+Environment:
+
+ Kernel mode, local to I/O system
+
+Revision History:
+
+
+--*/
+
+#include "halp.h"
+#include "bugcodes.h"
+#include "eisa.h"
+
+
+//
+// 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.
+//
+
+extern POBJECT_TYPE IoAdapterObjectType;
+
+extern BOOLEAN LessThan16Mb;
+
+PADAPTER_OBJECT MasterAdapterObject;
+
+extern PADAPTER_OBJECT HalpEisaAdapter[8];
+
+//
+// Map buffer prameters. These are initialized in HalInitSystem
+//
+
+extern PHYSICAL_ADDRESS HalpMapBufferPhysicalAddress;
+extern ULONG HalpMapBufferSize;
+
+ULONG
+HalpReadEisaData (
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+
+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;
+ BOOLEAN eisaSystem;
+ PHYSICAL_ADDRESS physicalAddress;
+
+ eisaSystem = HalpBusType == MACHINE_TYPE_EISA ? TRUE : FALSE;
+
+ 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 allocationg a new one.
+ //
+
+ MapBufferPhysicalAddress = HalpMapBufferPhysicalAddress.LowPart;
+
+ //
+ // Map the buffer for access.
+ //
+
+
+ // On an R4000 system, this space should be mapped with caches
+ // disabled to avoid having to perform page exports on IO writes
+ // and page purges on IO reads.
+
+ MapBufferVirtualAddress = MmMapIoSpace(
+ HalpMapBufferPhysicalAddress,
+ HalpMapBufferSize,
+ FALSE // Cache disabled.
+ );
+
+ if (MapBufferVirtualAddress == NULL) {
+
+ //
+ // The buffer could not be mapped.
+ //
+
+ HalpMapBufferSize = 0;
+
+ KeReleaseSpinLock( &AdapterObject->SpinLock, Irql );
+ return(FALSE);
+ }
+
+ } else {
+
+ //
+ // Allocate the map buffers.
+ //
+ physicalAddress.LowPart = MAXIMUM_PHYSICAL_ADDRESS - 1;
+ physicalAddress.HighPart = 0;
+ MapBufferVirtualAddress = MmAllocateContiguousMemory(
+ NumberOfPages * PAGE_SIZE,
+ physicalAddress
+ );
+
+ if (MapBufferVirtualAddress == NULL) {
+
+ KeReleaseSpinLock( &AdapterObject->SpinLock, Irql );
+ return(FALSE);
+ }
+
+ //
+ // Get the physical address of the map base.
+ //
+
+ MapBufferPhysicalAddress = MmGetPhysicalAddress(
+ MapBufferVirtualAddress
+ ).LowPart;
+
+ }
+
+ //
+ // Initailize the map registers where memory has been allocated.
+ //
+
+ TranslationEntry = ((PTRANSLATION_ENTRY) AdapterObject->MapRegisterBase) +
+ AdapterObject->NumberOfMapRegisters;
+
+ for (i = 0; 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 || (!eisaSystem &&
+ ((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 ) {
+
+ 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,
+ *((POBJECT_TYPE *)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,
+ *((POBJECT_TYPE *)IoAdapterObjectType),
+ KernelMode
+ );
+
+ }
+
+ //
+ // If the adapter object was successfully created, then attempt to insert
+ // it into the the object table.
+ //
+
+ if (NT_SUCCESS( Status )) {
+
+ Status = ObInsertObject( AdapterObject,
+ NULL,
+ FILE_READ_DATA | FILE_WRITE_DATA,
+ 0,
+ (PVOID *) NULL,
+ &Handle );
+
+ if (NT_SUCCESS( Status )) {
+
+ 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;
+
+}
+
+extern PVOID SecondaryCachePurgeBaseAddress;
+
+VOID
+HalpCopyBufferMap(
+ IN PMDL Mdl,
+ IN PTRANSLATION_ENTRY TranslationEntry,
+ IN PVOID CurrentVa,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice,
+ IN ULONG noncachedAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine copies the speicific data between the user's buffer and the
+ map register buffer. First a the user buffer is mapped if necessary, then
+ the data is copied. Finally the user buffer will be unmapped if
+ neccessary.
+
+Arguments:
+
+ Mdl - Pointer to the MDL that describes the pages of memory that are
+ being read or written.
+
+ TranslationEntry - The address of the base map register that has been
+ allocated to the device driver for use in mapping the transfer.
+
+ CurrentVa - Current virtual address in the buffer described by the MDL
+ that the transfer is being done to or from.
+
+ Length - The length of the transfer. This determines the number of map
+ registers that need to be written to map the transfer.
+
+ WriteToDevice - Boolean value that indicates whether this is a write
+ to the device from memory (TRUE), or vice versa.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PCCHAR bufferAddress;
+ PCCHAR mapAddress;
+ ULONG *p;
+ ULONG *q;
+ UCHAR *m;
+ UCHAR *n;
+ ULONG i;
+
+ //
+ // Get the system address of the MDL.
+ //
+
+ bufferAddress = MmGetSystemAddressForMdl(Mdl);
+
+ //
+ // Calculate the actual start of the buffer based on the system VA and
+ // the current VA.
+ //
+
+ bufferAddress += (PCCHAR) CurrentVa - (PCCHAR) MmGetMdlVirtualAddress(Mdl);
+
+ mapAddress = (PCCHAR) TranslationEntry->VirtualAddress +
+ BYTE_OFFSET(CurrentVa);
+
+ //
+ // Copy the data between the user buffer and map buffer
+ //
+
+ if (WriteToDevice) {
+
+ RtlMoveMemory( mapAddress, (PCCHAR)noncachedAddress, Length);
+
+// if ( ((ULONG)mapAddress & 0x03)==0 &&
+// ((ULONG)noncachedAddress & 0x03)==0 &&
+// (Length & 0x03)==0 ) {
+// p = (ULONG *)mapAddress;
+// q = (ULONG *)noncachedAddress;
+// for(i=0;i<Length;i+=4)
+// *(p++) = *(q++);
+// }
+// else {
+//
+// KdPrint(("HalpCopyBufferMap() : Unaligned copy\n"));
+//
+// m = (UCHAR *)mapAddress;
+// n = (UCHAR *)noncachedAddress;
+// for(i=0;i<Length;i++)
+// *(m++) = *(n++);
+// }
+
+ } else {
+
+ RtlMoveMemory( (PCCHAR)noncachedAddress, mapAddress, Length);
+
+// if ( ((ULONG)mapAddress & 0x03)==0 &&
+// ((ULONG)noncachedAddress & 0x03)==0 &&
+// (Length & 0x03)==0 ) {
+// q = (ULONG *)mapAddress;
+// p = (ULONG *)noncachedAddress;
+// for(i=0;i<Length;i+=4)
+// *(p++) = *(q++);
+// }
+// else {
+//
+// KdPrint(("HalpCopyBufferMap() : Unaligned copy\n"));
+//
+// n = (UCHAR *)mapAddress;
+// m = (UCHAR *)noncachedAddress;
+// for(i=0;i<Length;i++)
+// *(m++) = *(n++);
+// }
+
+ }
+
+}
+
+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);
+}
+
+PVOID
+HalAllocateCommonBuffer(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN ULONG Length,
+ OUT PPHYSICAL_ADDRESS LogicalAddress,
+ IN BOOLEAN CacheEnabled
+ )
+/*++
+
+Routine Description:
+
+ This function allocates the memory for a common buffer and maps so that it
+ can be accessed by a master device and the CPU.
+
+Arguments:
+
+ AdapterObject - Supplies a pointer to the adapter object used by this
+ device.
+
+ Length - Supplies the length of the common buffer to be allocated.
+
+ LogicalAddress - Returns the logical address of the common buffer.
+
+ CacheEnable - Indicates whether the memeory is cached or not.
+
+Return Value:
+
+ Returns the virtual address of the common buffer. If the buffer cannot be
+ allocated then NULL is returned.
+
+--*/
+
+{
+ PVOID virtualAddress;
+ PVOID mapRegisterBase;
+ ULONG numberOfMapRegisters;
+ ULONG mappedLength;
+ WAIT_CONTEXT_BLOCK wcb;
+ KEVENT allocationEvent;
+ NTSTATUS status;
+ PMDL mdl;
+ KIRQL irql;
+ PHYSICAL_ADDRESS PhysicalAddress;
+ PTRANSLATION_ENTRY translationEntry;
+ UCHAR SavedNeedsMapRegisters;
+ ULONG SavedMapRegistersPerChannel;
+ PADAPTER_OBJECT SavedMasterAdapter;
+
+ numberOfMapRegisters = BYTES_TO_PAGES(Length);
+
+ SavedNeedsMapRegisters = AdapterObject->NeedsMapRegisters;
+ SavedMapRegistersPerChannel = AdapterObject->MapRegistersPerChannel;
+ SavedMasterAdapter = AdapterObject->MasterAdapter;
+ AdapterObject->NeedsMapRegisters = TRUE;
+ AdapterObject->MapRegistersPerChannel = numberOfMapRegisters;
+ AdapterObject->MasterAdapter = MasterAdapterObject;
+
+ //
+ // Initialize an event.
+ //
+
+ KeInitializeEvent( &allocationEvent, NotificationEvent, FALSE);
+
+ //
+ // Initialize the wait context block. Use the device object to indicate
+ // where the map register base should be stored.
+ //
+
+ wcb.DeviceObject = &mapRegisterBase;
+ wcb.CurrentIrp = NULL;
+ wcb.DeviceContext = &allocationEvent;
+
+ //
+ // Allocate the adapter and the map registers.
+ //
+
+ KeRaiseIrql(DISPATCH_LEVEL, &irql);
+
+ status = HalAllocateAdapterChannel(
+ AdapterObject,
+ &wcb,
+ numberOfMapRegisters,
+ HalpAllocationRoutine
+ );
+
+ KeLowerIrql(irql);
+
+ if (!NT_SUCCESS(status)) {
+
+ //
+ // Cleanup and return NULL.
+ //
+
+ AdapterObject->NeedsMapRegisters = SavedNeedsMapRegisters;
+ AdapterObject->MapRegistersPerChannel = SavedMapRegistersPerChannel;
+ AdapterObject->MasterAdapter = SavedMasterAdapter;
+ return(NULL);
+
+ }
+
+ //
+ // Wait for the map registers to be allocated.
+ //
+
+ status = KeWaitForSingleObject(
+ &allocationEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status)) {
+
+ //
+ // Cleanup and return NULL.
+ //
+
+ AdapterObject->NeedsMapRegisters = SavedNeedsMapRegisters;
+ AdapterObject->MapRegistersPerChannel = SavedMapRegistersPerChannel;
+ AdapterObject->MasterAdapter = SavedMasterAdapter;
+ return(NULL);
+
+ }
+
+ translationEntry = (PTRANSLATION_ENTRY) ((ULONG)mapRegisterBase & ~NO_SCATTER_GATHER);
+ LogicalAddress->HighPart = 0;
+ LogicalAddress->LowPart = translationEntry->PhysicalAddress;
+ virtualAddress = (PVOID)(0xa0000000 | LogicalAddress->LowPart);
+
+ AdapterObject->NeedsMapRegisters = SavedNeedsMapRegisters;
+ AdapterObject->MapRegistersPerChannel = SavedMapRegistersPerChannel;
+ AdapterObject->MasterAdapter = SavedMasterAdapter;
+
+ return(virtualAddress);
+}
+
+BOOLEAN
+HalFlushCommonBuffer(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN ULONG Length,
+ IN PHYSICAL_ADDRESS LogicalAddress,
+ IN PVOID VirtualAddress
+ )
+/*++
+
+Routine Description:
+
+ This function is called to flush any hardware adapter buffers when the
+ driver needs to read data written by an I/O master device to a common
+ buffer.
+
+Arguments:
+
+ AdapterObject - Supplies a pointer to the adapter object used by this
+ device.
+
+ Length - Supplies the length of the common buffer. This should be the same
+ value used for the allocation of the buffer.
+
+ LogicalAddress - Supplies the logical address of the common buffer. This
+ must be the same value return by HalAllocateCommonBuffer.
+
+ VirtualAddress - Supplies the virtual address of the common buffer. This
+ must be the same value return by HalAllocateCommonBuffer.
+
+Return Value:
+
+ Returns TRUE if no errors were detected; otherwise, FALSE is return.
+
+--*/
+
+{
+
+ return(TRUE);
+
+}
+
+VOID
+HalFreeCommonBuffer(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN ULONG Length,
+ IN PHYSICAL_ADDRESS LogicalAddress,
+ IN PVOID VirtualAddress,
+ IN BOOLEAN CacheEnabled
+ )
+/*++
+
+Routine Description:
+
+ This function frees a common buffer and all of the resouces it uses.
+
+Arguments:
+
+ AdapterObject - Supplies a pointer to the adapter object used by this
+ device.
+
+ Length - Supplies the length of the common buffer. This should be the same
+ value used for the allocation of the buffer.
+
+ LogicalAddress - Supplies the logical address of the common buffer. This
+ must be the same value return by HalAllocateCommonBuffer.
+
+ VirtualAddress - Supplies the virtual address of the common buffer. This
+ must be the same value return by HalAllocateCommonBuffer.
+
+ CacheEnable - Indicates whether the memeory is cached or not.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PTRANSLATION_ENTRY mapRegisterBase;
+ ULONG numberOfMapRegisters;
+ ULONG mapRegisterNumber;
+ UCHAR SavedNeedsMapRegisters;
+ PADAPTER_OBJECT SavedMasterAdapter;
+
+ if (MasterAdapterObject != NULL) {
+
+ SavedNeedsMapRegisters = AdapterObject->NeedsMapRegisters;
+ SavedMasterAdapter = AdapterObject->MasterAdapter;
+ AdapterObject->NeedsMapRegisters = TRUE;
+ AdapterObject->MasterAdapter = MasterAdapterObject;
+
+ //
+ // Calculate the number of map registers, the map register number and
+ // the map register base.
+ //
+
+ numberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(VirtualAddress, Length);
+ mapRegisterNumber = (LogicalAddress.LowPart - HalpMapBufferPhysicalAddress.LowPart) >> PAGE_SHIFT;
+
+ mapRegisterBase = (PTRANSLATION_ENTRY) MasterAdapterObject->MapRegisterBase
+ + mapRegisterNumber;
+
+ //
+ // Free the map registers.
+ //
+
+ IoFreeMapRegisters(
+ AdapterObject,
+ (PVOID) mapRegisterBase,
+ numberOfMapRegisters
+ );
+
+ AdapterObject->NeedsMapRegisters = SavedNeedsMapRegisters;
+ AdapterObject->MasterAdapter = SavedMasterAdapter;
+
+ }
+
+ return;
+
+}
+
+VOID
+IoFreeAdapterChannel(
+ IN PADAPTER_OBJECT AdapterObject
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is invoked to deallocate the specified adapter object.
+ Any map registers that were allocated are also automatically deallocated.
+ No checks are made to ensure that the adapter is really allocated to
+ a device object. However, if it is not, then kernel will bugcheck.
+
+ If another device is waiting in the queue to allocate the adapter object
+ it will be pulled from the queue and its execution routine will be
+ invoked.
+
+Arguments:
+
+ AdapterObject - Pointer to the adapter object to be deallocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PKDEVICE_QUEUE_ENTRY Packet;
+ PWAIT_CONTEXT_BLOCK Wcb;
+ PADAPTER_OBJECT MasterAdapter;
+ BOOLEAN Busy = FALSE;
+ IO_ALLOCATION_ACTION Action;
+ KIRQL Irql;
+ LONG MapRegisterNumber;
+
+ //
+ // Begin by getting the address of the master adapter.
+ //
+
+ MasterAdapter = AdapterObject->MasterAdapter;
+
+ //
+ // Pull requests of the adapter's device wait queue as long as the
+ // adapter is free and there are sufficient map registers available.
+ //
+
+ while( TRUE ) {
+
+ //
+ // Begin by checking to see whether there are any map registers that
+ // need to be deallocated. If so, then deallocate them now.
+ //
+
+ if (AdapterObject->NumberOfMapRegisters != 0) {
+ IoFreeMapRegisters( AdapterObject,
+ AdapterObject->MapRegisterBase,
+ AdapterObject->NumberOfMapRegisters
+ );
+ }
+
+ //
+ // Simply remove the next entry from the adapter's device wait queue.
+ // If one was successfully removed, allocate any map registers that it
+ // requires and invoke its execution routine.
+ //
+
+ Packet = KeRemoveDeviceQueue( &AdapterObject->ChannelWaitQueue );
+ if (Packet == NULL) {
+
+ //
+ // There are no more requests break out of the loop.
+ //
+
+ break;
+ }
+
+ Wcb = CONTAINING_RECORD( Packet,
+ WAIT_CONTEXT_BLOCK,
+ WaitQueueEntry );
+
+ AdapterObject->CurrentWcb = Wcb;
+ AdapterObject->NumberOfMapRegisters = Wcb->NumberOfMapRegisters;
+
+ //
+ // Check to see whether this driver wishes to allocate any map
+ // registers. If so, then queue the device object to the master
+ // adapter queue to wait for them to become available. If the driver
+ // wants map registers, ensure that this adapter has enough total
+ // map registers to satisfy the request.
+ //
+
+ if (Wcb->NumberOfMapRegisters != 0 &&
+ AdapterObject->MasterAdapter != NULL) {
+
+ //
+ // Lock the map register bit map and the adapter queue in the
+ // master adapter object. The channel structure offset is used as
+ // a hint for the register search.
+ //
+
+ KeAcquireSpinLock( &MasterAdapter->SpinLock, &Irql );
+
+ MapRegisterNumber = -1;
+
+ if (IsListEmpty( &MasterAdapter->AdapterQueue)) {
+ MapRegisterNumber = RtlFindClearBitsAndSet( MasterAdapter->MapRegisters,
+ Wcb->NumberOfMapRegisters,
+ 0
+ );
+ }
+ if (MapRegisterNumber == -1) {
+
+ //
+ // There were not enough free map registers. Queue this request
+ // on the master adapter where is will wait until some registers
+ // are deallocated.
+ //
+
+ InsertTailList( &MasterAdapter->AdapterQueue,
+ &AdapterObject->AdapterQueue
+ );
+ Busy = 1;
+
+ } else {
+
+ AdapterObject->MapRegisterBase = (PVOID)((PTRANSLATION_ENTRY)
+ MasterAdapter->MapRegisterBase + MapRegisterNumber);
+
+ //
+ // Set the no scatter/gather flag if scatter/gather not
+ // supported.
+ //
+
+ if (!AdapterObject->ScatterGather) {
+
+ AdapterObject->MapRegisterBase = (PVOID)
+ ((ULONG) AdapterObject->MapRegisterBase | NO_SCATTER_GATHER);
+
+ }
+ }
+
+ KeReleaseSpinLock( &MasterAdapter->SpinLock, Irql );
+
+ } else {
+
+ AdapterObject->MapRegisterBase = NULL;
+ AdapterObject->NumberOfMapRegisters = 0;
+
+ }
+
+ //
+ // If there were either enough map registers available or no map
+ // registers needed to be allocated, invoke the driver's execution
+ // routine now.
+ //
+
+ if (!Busy) {
+ AdapterObject->CurrentWcb = Wcb;
+ Action = Wcb->DeviceRoutine( Wcb->DeviceObject,
+ Wcb->CurrentIrp,
+ AdapterObject->MapRegisterBase,
+ Wcb->DeviceContext );
+
+ //
+ // If the execution routine would like to have the adapter
+ // deallocated, then release the adapter object.
+ //
+
+ if (Action == KeepObject) {
+
+ //
+ // This request wants to keep the channel a while so break
+ // out of the loop.
+ //
+
+ break;
+
+ }
+
+ //
+ // If the driver wants to keep the map registers then set the
+ // number allocated to 0. This keeps the deallocation routine
+ // from deallocating them.
+ //
+
+ if (Action == DeallocateObjectKeepRegisters) {
+ AdapterObject->NumberOfMapRegisters = 0;
+ }
+
+ } else {
+
+ //
+ // This request did not get the requested number of map registers so
+ // out of the loop.
+ //
+
+ break;
+ }
+ }
+}
+
+VOID
+IoFreeMapRegisters(
+ PADAPTER_OBJECT AdapterObject,
+ PVOID MapRegisterBase,
+ ULONG NumberOfMapRegisters
+ )
+/*++
+
+Routine Description:
+
+ This routine deallocates the map registers for the adapter. If there are
+ any queued adapter waiting for an attempt is made to allocate the next
+ entry.
+
+Arguments:
+
+ AdapterObject - The adapter object to where the map register should be
+ returned.
+
+ MapRegisterBase - The map register base of the registers to be deallocated.
+
+ NumberOfMapRegisters - The number of registers to be deallocated.
+
+Return Value:
+
+ None
+
+--+*/
+{
+ PADAPTER_OBJECT MasterAdapter;
+ LONG MapRegisterNumber;
+ PWAIT_CONTEXT_BLOCK Wcb;
+ PLIST_ENTRY Packet;
+ IO_ALLOCATION_ACTION Action;
+ KIRQL Irql;
+
+
+ //
+ // Begin by getting the address of the master adapter.
+ //
+
+ if (AdapterObject->MasterAdapter != NULL && MapRegisterBase != NULL) {
+
+ MasterAdapter = AdapterObject->MasterAdapter;
+
+ } else {
+
+ //
+ // There are no map registers to return.
+ //
+
+ return;
+ }
+
+ //
+ // Strip no scatter/gather flag.
+ //
+
+ MapRegisterBase = (PVOID) ((ULONG) MapRegisterBase & ~NO_SCATTER_GATHER);
+
+ MapRegisterNumber = (PTRANSLATION_ENTRY) MapRegisterBase -
+ (PTRANSLATION_ENTRY) MasterAdapter->MapRegisterBase;
+
+ //
+ // Acquire the master adapter spinlock which locks the adapter queue and the
+ // bit map for the map registers.
+ //
+
+ KeAcquireSpinLock(&MasterAdapter->SpinLock, &Irql);
+
+ //
+ // Return the registers to the bit map.
+ //
+
+ RtlClearBits( MasterAdapter->MapRegisters,
+ MapRegisterNumber,
+ NumberOfMapRegisters
+ );
+
+ //
+ // Process any requests waiting for map registers in the adapter queue.
+ // Requests are processed until a request cannot be satisfied or until
+ // there are no more requests in the queue.
+ //
+
+ while(TRUE) {
+
+ if ( IsListEmpty(&MasterAdapter->AdapterQueue) ){
+ break;
+ }
+
+ Packet = RemoveHeadList( &MasterAdapter->AdapterQueue );
+ AdapterObject = CONTAINING_RECORD( Packet,
+ ADAPTER_OBJECT,
+ AdapterQueue
+ );
+ Wcb = AdapterObject->CurrentWcb;
+
+ //
+ // Attempt to allocate map registers for this request. Use the previous
+ // register base as a hint.
+ //
+
+ MapRegisterNumber = RtlFindClearBitsAndSet( MasterAdapter->MapRegisters,
+ AdapterObject->NumberOfMapRegisters,
+ MasterAdapter->NumberOfMapRegisters
+ );
+
+ if (MapRegisterNumber == -1) {
+
+ //
+ // There were not enough free map registers. Put this request back on
+ // the adapter queue where is came from.
+ //
+
+ InsertHeadList( &MasterAdapter->AdapterQueue,
+ &AdapterObject->AdapterQueue
+ );
+
+ break;
+
+ }
+
+ KeReleaseSpinLock( &MasterAdapter->SpinLock, Irql );
+
+ AdapterObject->MapRegisterBase = (PVOID) ((PTRANSLATION_ENTRY)
+ MasterAdapter->MapRegisterBase + MapRegisterNumber);
+
+ //
+ // Set the no scatter/gather flag if scatter/gather not
+ // supported.
+ //
+
+ if (!AdapterObject->ScatterGather) {
+
+ AdapterObject->MapRegisterBase = (PVOID)
+ ((ULONG) AdapterObject->MapRegisterBase | NO_SCATTER_GATHER);
+
+ }
+
+ //
+ // Invoke the driver's execution routine now.
+ //
+
+ Action = Wcb->DeviceRoutine( Wcb->DeviceObject,
+ Wcb->CurrentIrp,
+ AdapterObject->MapRegisterBase,
+ Wcb->DeviceContext );
+
+ //
+ // If the driver wishes to keep the map registers then set the number
+ // allocated to zero and set the action to deallocate object.
+ //
+
+ if (Action == DeallocateObjectKeepRegisters) {
+ AdapterObject->NumberOfMapRegisters = 0;
+ Action = DeallocateObject;
+ }
+
+ //
+ // If the driver would like to have the adapter deallocated,
+ // then deallocate any map registers allocated and then release
+ // the adapter object.
+ //
+
+ if (Action == DeallocateObject) {
+
+ //
+ // The map registers registers are deallocated here rather than in
+ // IoFreeAdapterChannel. This limits the number of times
+ // this routine can be called recursively possibly overflowing
+ // the stack. The worst case occurs if there is a pending
+ // request for the adapter that uses map registers and whos
+ // excution routine decallocates the adapter. In that case if there
+ // are no requests in the master adapter queue, then IoFreeMapRegisters
+ // will get called again.
+ //
+
+ if (AdapterObject->NumberOfMapRegisters != 0) {
+
+ //
+ // Deallocate the map registers and clear the count so that
+ // IoFreeAdapterChannel will not deallocate them again.
+ //
+
+ KeAcquireSpinLock( &MasterAdapter->SpinLock, &Irql );
+
+ RtlClearBits( MasterAdapter->MapRegisters,
+ MapRegisterNumber,
+ AdapterObject->NumberOfMapRegisters
+ );
+
+ AdapterObject->NumberOfMapRegisters = 0;
+
+ KeReleaseSpinLock( &MasterAdapter->SpinLock, Irql );
+ }
+
+ IoFreeAdapterChannel( AdapterObject );
+ }
+
+ KeAcquireSpinLock( &MasterAdapter->SpinLock, &Irql );
+
+ }
+
+ KeReleaseSpinLock( &MasterAdapter->SpinLock, Irql );
+}
+
+BOOLEAN
+HalTranslateBusAddress(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN PHYSICAL_ADDRESS BusAddress,
+ IN OUT PULONG AddressSpace,
+ OUT PPHYSICAL_ADDRESS TranslatedAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the system physical address for a specified I/O bus
+ address. The return value is suitable for use in a subsequent call to
+ MmMapIoSpace.
+
+Arguments:
+
+ InterfaceType - Supplies the type of bus which the address is for.
+
+ BusNumber - Supplies the bus number for the device.
+
+ BusAddress - Supplies the bus relative address.
+
+ AddressSpace - Supplies the address space number for the device: 0 for
+ memory and 1 for I/O space. Returns the address space on this system.
+
+ TranslatedAddress - Supplies a pointer to return the translated address
+
+Return Value:
+
+ A return value of TRUE indicates that a system physical address
+ corresponding to the supplied bus relative address and bus address
+ number has been returned in TranslatedAddress.
+
+ A return value of FALSE occurs if the translation for the address was
+ not possible
+
+--*/
+
+{
+ TranslatedAddress->HighPart = 0;
+
+ //
+ // If this is for the internal bus then just return the passed parameter.
+ //
+
+ if (InterfaceType != Isa && InterfaceType != Eisa && InterfaceType != Internal) {
+
+ //
+ // Not on this system return nothing.
+ //
+
+ *AddressSpace = 0;
+ TranslatedAddress->LowPart = 0;
+ return(FALSE);
+ }
+
+ //
+ // Jazz 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.
+ //
+
+ if (*AddressSpace) {
+
+ //
+ // The address is in I/O space.
+ //
+
+ *AddressSpace = 0;
+ TranslatedAddress->LowPart = BusAddress.LowPart + EISA_CONTROL_PHYSICAL_BASE;
+ if (TranslatedAddress->LowPart < BusAddress.LowPart) {
+
+ //
+ // A carry occurred.
+ //
+
+ TranslatedAddress->HighPart = 1;
+ }
+ return(TRUE);
+
+ } else {
+
+ //
+ // The address is in memory space.
+ //
+
+ *AddressSpace = 0;
+ TranslatedAddress->LowPart = BusAddress.LowPart + EISA_MEMORY_PHYSICAL_BASE;
+ if (TranslatedAddress->LowPart < BusAddress.LowPart) {
+
+ //
+ // A carry occurred.
+ //
+
+ TranslatedAddress->HighPart = 1;
+ }
+ return(TRUE);
+
+ }
+}
+
+ULONG
+HalGetBusData(
+ IN BUS_DATA_TYPE BusDataType,
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ Subset of HalGetBusDataByOffset, just pass the request along.
+
+--*/
+{
+ return HalGetBusDataByOffset (
+ BusDataType,
+ BusNumber,
+ SlotNumber,
+ Buffer,
+ 0,
+ Length
+ );
+}
+
+ULONG
+HalGetBusDataByOffset(
+ IN BUS_DATA_TYPE BusDataType,
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ The function returns the bus data for a slot or address.
+
+Arguments:
+
+ BusDataType - Supplies the type of bus.
+
+ BusNumber - Indicates which bus.
+
+ Buffer - Supplies the space to store the data.
+
+ Length - Supplies a count in bytes of the maximum amount to return.
+
+Return Value:
+
+ Returns the amount of data stored into the buffer.
+
+--*/
+
+{
+
+ ULONG DataLength = 0;
+
+ switch (BusDataType) {
+ case EisaConfiguration:
+ DataLength = HalpReadEisaData(BusNumber, SlotNumber, Buffer, Offset, Length);
+ break;
+ }
+
+ return(DataLength);
+
+}
+
+ULONG
+HalSetBusData(
+ IN BUS_DATA_TYPE BusDataType,
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ Subset of HalGetBusDataByOffset, just pass the request along.
+
+--*/
+{
+ return HalSetBusDataByOffset(
+ BusDataType,
+ BusNumber,
+ SlotNumber,
+ Buffer,
+ 0,
+ Length
+ );
+}
+
+ULONG
+HalSetBusDataByOffset(
+ IN BUS_DATA_TYPE BusDataType,
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ The function sets the bus data for a slot or address.
+
+Arguments:
+
+ BusDataType - Supplies the type of bus.
+
+ BusNumber - Indicates which bus.
+
+ Buffer - Supplies the space to store the data.
+
+ Length - Supplies a count in bytes of the maximum amount to return.
+
+Return Value:
+
+ Returns the amount of data stored into the buffer.
+
+--*/
+{
+ return 0;
+}
+
+NTSTATUS
+HalAssignSlotResources (
+ IN PUNICODE_STRING RegistryPath,
+ IN PUNICODE_STRING DriverClassName OPTIONAL,
+ IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT DeviceObject OPTIONAL,
+ IN INTERFACE_TYPE BusType,
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN OUT PCM_RESOURCE_LIST *AllocatedResources
+ )
+/*++
+
+Routine Description:
+
+ Reads the targeted device to determine it's required resources.
+ Calls IoAssignResources to allocate them.
+ Sets the targeted device with it's assigned resoruces
+ and returns the assignments to the caller.
+
+Arguments:
+
+ RegistryPath - Passed to IoAssignResources.
+ A device specific registry path in the current-control-set, used
+ to check for pre-assigned settings and to track various resource
+ assignment information for this device.
+
+ DriverClassName Used to report the assigned resources for the driver/device
+ DriverObject - Used to report the assigned resources for the driver/device
+ DeviceObject - Used to report the assigned resources for the driver/device
+ (ie, IoReportResoruceUsage)
+ BusType
+ BusNumber
+ SlotNumber - Together BusType,BusNumber,SlotNumber uniquely
+ indentify the device to be queried & set.
+
+Return Value:
+
+ STATUS_SUCCESS or error
+
+--*/
+{
+ //
+ // This HAL doesn't support any buses which support
+ // HalAssignSlotResources
+ //
+
+ return STATUS_NOT_SUPPORTED;
+
+}
+
+NTSTATUS
+HalAdjustResourceList (
+ IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList
+ )
+/*++
+
+Routine Description:
+
+ Takes the pResourceList and limits any requested resource to
+ it's corrisponding bus requirements.
+
+Arguments:
+
+ pResourceList - The resource list to adjust.
+
+Return Value:
+
+ STATUS_SUCCESS or error
+
+--*/
+{
+ //
+ // BUGBUG: This function should verify that the resoruces fit
+ // the bus requirements - for now we will assume that the bus
+ // can support anything the device may ask for.
+ //
+
+ return STATUS_SUCCESS;
+}
+
+BOOLEAN
+HalpCreateDmaStructures (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the structures necessary for DMA operations
+ and connects the intermediate interrupt dispatcher. It also connects
+ an interrupt handler to the DMA channel interrupt.
+
+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.
+
+--*/
+
+{
+
+ //
+ // Initialize EISA bus interrupts.
+ //
+
+ return HalpCreateEisaStructures();
+
+}
+
+ULONG
+HalpReadEisaData (
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ The function returns the Eisa bus data for a slot or address.
+
+Arguments:
+
+ BusDataType - Supplies the type of bus.
+
+ BusNumber - Indicates which bus.
+
+ Buffer - Supplies the space to store the data.
+
+ Length - Supplies a count in bytes of the maximum amount to return.
+
+Return Value:
+
+ Returns the amount of data stored into the buffer.
+
+--*/
+
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ OBJECT_ATTRIBUTES BusObjectAttributes;
+ PWSTR EisaPath = L"\\Registry\\Machine\\Hardware\\Description\\System\\EisaAdapter";
+ PWSTR ConfigData = L"Configuration Data";
+ ANSI_STRING TmpString;
+ UCHAR BusString[] = "00";
+ UNICODE_STRING RootName, BusName;
+ UNICODE_STRING ConfigDataName;
+ NTSTATUS NtStatus;
+ PKEY_VALUE_FULL_INFORMATION ValueInformation;
+ PCM_FULL_RESOURCE_DESCRIPTOR Descriptor;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialResource;
+ PCM_EISA_SLOT_INFORMATION SlotInformation;
+ ULONG PartialCount;
+ ULONG TotalDataSize, SlotDataSize;
+ HANDLE EisaHandle, BusHandle;
+ ULONG BytesWritten, BytesNeeded;
+ PUCHAR KeyValueBuffer;
+ ULONG i;
+ ULONG DataLength = 0;
+ PUCHAR DataBuffer = Buffer;
+ BOOLEAN Found = FALSE;
+
+
+ RtlInitUnicodeString(
+ &RootName,
+ EisaPath
+ );
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &RootName,
+ OBJ_CASE_INSENSITIVE,
+ (HANDLE)NULL,
+ NULL
+ );
+
+ //
+ // Open the EISA root
+ //
+
+ NtStatus = ZwOpenKey(
+ &EisaHandle,
+ KEY_READ,
+ &ObjectAttributes
+ );
+
+ if (!NT_SUCCESS(NtStatus)) {
+ KdPrint(("HAL: Open Status = %x\n",NtStatus));
+ return(0);
+ }
+
+ //
+ // Init bus number path
+ //
+
+ if (BusNumber > 99) {
+ return (0);
+ }
+
+ if (BusNumber > 9) {
+ BusString[0] += (UCHAR) (BusNumber/10);
+ BusString[1] += (UCHAR) (BusNumber % 10);
+ } else {
+ BusString[0] += (UCHAR) BusNumber;
+ BusString[1] = '\0';
+ }
+
+ RtlInitAnsiString(
+ &TmpString,
+ BusString
+ );
+
+ RtlAnsiStringToUnicodeString(
+ &BusName,
+ &TmpString,
+ TRUE
+ );
+
+
+ InitializeObjectAttributes(
+ &BusObjectAttributes,
+ &BusName,
+ OBJ_CASE_INSENSITIVE,
+ (HANDLE)EisaHandle,
+ NULL
+ );
+
+ //
+ // Open the EISA root + Bus Number
+ //
+
+ NtStatus = ZwOpenKey(
+ &BusHandle,
+ KEY_READ,
+ &BusObjectAttributes
+ );
+
+ if (!NT_SUCCESS(NtStatus)) {
+ KdPrint(("HAL: Opening Bus Number: Status = %x\n",NtStatus));
+ return(0);
+ }
+
+ //
+ // opening the configuration data. This first call tells us how
+ // much memory we need to allocate
+ //
+
+ RtlInitUnicodeString(
+ &ConfigDataName,
+ ConfigData
+ );
+
+ //
+ // This should fail. We need to make this call so we can
+ // get the actual size of the buffer to allocate.
+ //
+
+ NtStatus = ZwQueryValueKey(
+ BusHandle,
+ &ConfigDataName,
+ KeyValueFullInformation,
+ ValueInformation,
+ 0,
+ &BytesNeeded
+ );
+
+ KeyValueBuffer = ExAllocatePool(
+ NonPagedPool,
+ BytesNeeded
+ );
+
+ if (KeyValueBuffer == NULL) {
+ KdPrint(("HAL: Cannot allocate Key Value Buffer\n"));
+ ZwClose(BusHandle);
+ return(0);
+ }
+
+ ValueInformation = (PKEY_VALUE_FULL_INFORMATION)KeyValueBuffer;
+
+ NtStatus = ZwQueryValueKey(
+ BusHandle,
+ &ConfigDataName,
+ KeyValueFullInformation,
+ ValueInformation,
+ BytesNeeded,
+ &BytesWritten
+ );
+
+
+ ZwClose(BusHandle);
+
+ if (!NT_SUCCESS(NtStatus) || ValueInformation->DataLength == 0) {
+ KdPrint(("HAL: Query Config Data: Status = %x\n",NtStatus));
+ ExFreePool(KeyValueBuffer);
+ return(0);
+ }
+
+
+ //
+ // We get back a Full Resource Descriptor List
+ //
+
+ Descriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PUCHAR)ValueInformation +
+ ValueInformation->DataOffset);
+
+ PartialResource = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)
+ &(Descriptor->PartialResourceList.PartialDescriptors);
+ PartialCount = Descriptor->PartialResourceList.Count;
+
+ for (i = 0; i < PartialCount; i++) {
+
+ //
+ // Do each partial Resource
+ //
+
+ switch (PartialResource->Type) {
+ case CmResourceTypeNull:
+ case CmResourceTypePort:
+ case CmResourceTypeInterrupt:
+ case CmResourceTypeMemory:
+ case CmResourceTypeDma:
+
+ //
+ // We dont care about these.
+ //
+
+ PartialResource++;
+
+ break;
+
+ case CmResourceTypeDeviceSpecific:
+
+ //
+ // Bingo!
+ //
+
+ TotalDataSize = PartialResource->u.DeviceSpecificData.DataSize;
+
+ SlotInformation = (PCM_EISA_SLOT_INFORMATION)
+ ((PUCHAR)PartialResource +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
+
+ while (((LONG)TotalDataSize) > 0) {
+
+ if (SlotInformation->ReturnCode == EISA_EMPTY_SLOT) {
+
+ SlotDataSize = sizeof(CM_EISA_SLOT_INFORMATION);
+
+ } else {
+
+ SlotDataSize = sizeof(CM_EISA_SLOT_INFORMATION) +
+ SlotInformation->NumberFunctions *
+ sizeof(CM_EISA_FUNCTION_INFORMATION);
+ }
+
+ if (SlotDataSize > TotalDataSize) {
+
+ //
+ // Something is wrong again
+ //
+
+ ExFreePool(KeyValueBuffer);
+ return(0);
+
+ }
+
+ if (SlotNumber != 0) {
+
+ SlotNumber--;
+
+ SlotInformation = (PCM_EISA_SLOT_INFORMATION)
+ ((PUCHAR)SlotInformation + SlotDataSize);
+
+ TotalDataSize -= SlotDataSize;
+
+ continue;
+
+ }
+
+ //
+ // This is our slot
+ //
+
+ Found = TRUE;
+ break;
+
+ }
+
+ //
+ // End loop
+ //
+
+ i = PartialCount;
+
+ break;
+
+ default:
+ KdPrint(("Bad Data in registry!\n"));
+ ExFreePool(KeyValueBuffer);
+ return(0);
+ }
+ }
+
+ if (Found) {
+
+ i = Length + Offset;
+ if (i > SlotDataSize) {
+ i = SlotDataSize;
+ }
+
+ DataLength = i - Offset;
+ RtlMoveMemory (Buffer, ((PUCHAR)SlotInformation + Offset), DataLength);
+
+ }
+
+ ExFreePool(KeyValueBuffer);
+ return DataLength;
+}
diff --git a/private/ntos/nthals/haldti/mips/jxmapio.c b/private/ntos/nthals/haldti/mips/jxmapio.c
new file mode 100644
index 000000000..48fc44aa8
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/jxmapio.c
@@ -0,0 +1,78 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ jxmapio.c
+
+Abstract:
+
+ This module implements the mapping of HAL I/O space a MIPS R3000
+ or R4000 Jazz system.
+
+Author:
+
+ David N. Cutler (davec) 28-Apr-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+
+
+#define REAL_TIME_CLOCK_ADDRESS 0x71
+
+//
+// Define global data used to locate the EISA control space and the realtime
+// clock registers.
+//
+
+PVOID HalpEisaControlBase;
+PVOID HalpEisaMemoryBase;
+PVOID HalpRealTimeClockBase;
+
+
+BOOLEAN
+HalpMapIoSpace (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine maps the HAL I/O space for a MIPS R3000 or R4000 Jazz
+ system.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ If the initialization is successfully completed, than a value of TRUE
+ is returned. Otherwise, a value of FALSE is returned.
+
+--*/
+
+{
+
+ // For ARCStation I, Eisa I/O Space can be accessed through KSEG1.
+ // So, HalpEisaControlBase can be computed by ORing the base address
+ // of KSEG1 with the base physical address of EISA I/O space.
+ // HalpRealTimeClockBase can be computed in a similar manner.
+
+ HalpEisaControlBase = (PVOID)(KSEG1_BASE | EISA_CONTROL_PHYSICAL_BASE);
+
+ HalpEisaMemoryBase = (PVOID)(KSEG1_BASE | EISA_MEMORY_PHYSICAL_BASE);
+
+ HalpRealTimeClockBase = (PVOID)(KSEG1_BASE | EISA_CONTROL_PHYSICAL_BASE | REAL_TIME_CLOCK_ADDRESS);
+
+ return TRUE;
+}
diff --git a/private/ntos/nthals/haldti/mips/jxport.c b/private/ntos/nthals/haldti/mips/jxport.c
new file mode 100644
index 000000000..afc9c4dca
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/jxport.c
@@ -0,0 +1,773 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ jxport.c
+
+Abstract:
+
+ This module implements the code that provides communication between
+ the kernel debugger on a MIPS R3000 or R4000 Jazz system and the host
+ system.
+
+Author:
+
+ David N. Cutler (davec) 28-Apr-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "jazzserp.h"
+
+VOID
+HalpGetDivisorFromBaud(
+ IN ULONG ClockRate,
+ IN LONG DesiredBaud,
+ OUT PSHORT AppropriateDivisor
+ );
+
+
+#pragma alloc_text(INIT,HalpGetDivisorFromBaud)
+
+//
+// BUGBUG Temporarily, we use counter to do the timeout
+//
+
+#define TIMEOUT_COUNT 1024*512
+
+//
+// BUGBUG Temp until we have a configuration manager.
+//
+
+PUCHAR KdComPortInUse = NULL;
+BOOLEAN KdUseModemControl = FALSE;
+
+//
+// Define serial port read and write addresses.
+//
+
+// Assume COM1 for the kernel debugger.
+
+#define SERIAL_PORT_ADDRESS 0x3f8
+
+#define SP_READ ((PSP_READ_REGISTERS)(KSEG1_BASE | EISA_CONTROL_PHYSICAL_BASE | SERIAL_PORT_ADDRESS))
+#define SP_WRITE ((PSP_WRITE_REGISTERS)(KSEG1_BASE | EISA_CONTROL_PHYSICAL_BASE | SERIAL_PORT_ADDRESS))
+
+//
+// Define forward referenced prototypes.
+//
+
+SP_LINE_STATUS
+KdReadLsr (
+ IN BOOLEAN WaitReason
+ );
+
+//
+// Define baud rate divisor to be used on the debugger port.
+//
+
+SHORT HalpBaudRateDivisor = 6;
+
+
+ULONG
+HalpGetByte (
+ IN PCHAR Input,
+ IN BOOLEAN Wait
+ )
+
+/*++
+
+Routine Description:
+
+ This routine gets a byte from the serial port used by the kernel
+ debugger.
+
+Arguments:
+
+ Input - Supplies a pointer to a variable that receives the input
+ data byte.
+
+ Wait - Supplies a boolean value that detemines whether a timeout
+ is applied to the input operation.
+
+Return Value:
+
+ CP_GET_SUCCESS is returned if a byte is successfully read from the
+ kernel debugger line.
+
+ CP_GET_ERROR is returned if an error is encountered during reading.
+
+ CP_GET_NODATA is returned if timeout occurs.
+
+--*/
+
+{
+
+ SP_LINE_STATUS LsrByte;
+ UCHAR DataByte;
+ ULONG TimeoutCount;
+
+ //
+ // Attempt to read a byte from the debugger port until a byte is
+ // available or until a timeout occurs.
+ //
+
+ TimeoutCount = Wait ? TIMEOUT_COUNT : 1;
+ do {
+ TimeoutCount -= 1;
+
+ //
+ // Wait until data is available in the receive buffer.
+ //
+
+ KeStallExecutionProcessor(1);
+ LsrByte = KdReadLsr(TRUE);
+ if (LsrByte.DataReady == 0) {
+ continue;
+ }
+
+ //
+ // Read input byte and store in callers buffer.
+ //
+
+ *Input = READ_REGISTER_UCHAR(&SP_READ->ReceiveBuffer);
+
+ //
+ // If using modem controls, then skip any incoming data while
+ // ReceiveData not set.
+ //
+
+ if (KdUseModemControl) {
+ DataByte = READ_REGISTER_UCHAR(&SP_READ->ModemStatus);
+ if ( ((PSP_MODEM_STATUS)&DataByte)->ReceiveDetect == 0) {
+ continue;
+ }
+ }
+
+ //
+ // Return function value as the not of the error indicators.
+ //
+
+ if (LsrByte.ParityError ||
+ LsrByte.FramingError ||
+ LsrByte.OverrunError ||
+ LsrByte.BreakIndicator) {
+ return CP_GET_ERROR;
+ }
+
+ return CP_GET_SUCCESS;
+ } while(TimeoutCount != 0);
+
+ return CP_GET_NODATA;
+}
+
+BOOLEAN
+KdPortInitialize (
+ PDEBUG_PARAMETERS DebugParameters,
+ PLOADER_PARAMETER_BLOCK LoaderBlock,
+ BOOLEAN Initialize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the serial port used by the kernel debugger
+ and must be called during system initialization.
+
+Arguments:
+
+ DebugParameter - Supplies a pointer to the debug port parameters.
+
+ LoaderBlock - Supplies a pointer to the loader parameter block.
+
+ Initialize - Specifies a boolean value that determines whether the
+ debug port is initialized or just the debug port parameters
+ are captured.
+
+Return Value:
+
+ A value of TRUE is returned is the port was successfully initialized.
+ Otherwise, a value of FALSE is returned.
+
+--*/
+
+{
+
+ PCONFIGURATION_COMPONENT_DATA ConfigurationEntry;
+ UCHAR DataByte;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
+ PCM_SERIAL_DEVICE_DATA DeviceData;
+ ULONG KdPortEntry;
+ PCM_PARTIAL_RESOURCE_LIST List;
+ ULONG MatchKey;
+ ULONG BaudRate;
+ ULONG BaudClock;
+
+ //
+ // Find the configuration information for the first serial port.
+ //
+
+ if (LoaderBlock != NULL) {
+ MatchKey = 0;
+ ConfigurationEntry = KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot,
+ ControllerClass,
+ SerialController,
+ &MatchKey);
+
+ } else {
+ ConfigurationEntry = NULL;
+ }
+
+ if (DebugParameters->BaudRate != 0) {
+ BaudRate = DebugParameters->BaudRate;
+ } else {
+ BaudRate = 19200;
+ }
+
+ //
+ // If the serial configuration entry was not found or the frequency
+ // specified is not supported, then default the baud clock to 1843200.
+ //
+
+ 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;
+ }
+ }
+
+ HalpGetDivisorFromBaud(
+ BaudClock,
+ BaudRate,
+ &HalpBaudRateDivisor
+ );
+
+ //
+ // If the debugger is not being enabled, then return.
+ //
+
+ if (Initialize == FALSE) {
+ return TRUE;
+ }
+
+ KdComPortInUse=(PUCHAR)(SERIAL_PORT_ADDRESS);
+
+ //
+ // Clear the divisor latch, clear all interrupt enables, and reset and
+ // disable the FIFO's.
+ //
+
+ WRITE_REGISTER_UCHAR(&SP_WRITE->LineControl, 0x0);
+ WRITE_REGISTER_UCHAR(&SP_WRITE->InterruptEnable, 0x0);
+ DataByte = 0;
+ ((PSP_FIFO_CONTROL)(&DataByte))->ReceiveFifoReset = 1;
+ ((PSP_FIFO_CONTROL)(&DataByte))->TransmitFifoReset = 1;
+ WRITE_REGISTER_UCHAR(&SP_WRITE->FifoControl, DataByte);
+
+ //
+ // Set the divisor latch and set the baud rate to 19200 baud.
+ //
+ ((PSP_LINE_CONTROL)(&DataByte))->DivisorLatch = 1;
+ WRITE_REGISTER_UCHAR(&SP_WRITE->LineControl, DataByte);
+ WRITE_REGISTER_UCHAR(&SP_WRITE->TransmitBuffer, (UCHAR)(HalpBaudRateDivisor&0xff));
+ WRITE_REGISTER_UCHAR(&SP_WRITE->InterruptEnable, (UCHAR)(HalpBaudRateDivisor>>8));
+
+ //
+ // Clear the divisor latch and set the character size to eight bits
+ // with one stop bit and no parity checking.
+ //
+
+ DataByte = 0;
+ ((PSP_LINE_CONTROL)(&DataByte))->CharacterSize = EIGHT_BITS;
+ WRITE_REGISTER_UCHAR(&SP_WRITE->LineControl, DataByte);
+
+ //
+ // Set data terminal ready and request to send.
+ //
+
+ DataByte = 0;
+ ((PSP_MODEM_CONTROL)(&DataByte))->DataTerminalReady = 1;
+ ((PSP_MODEM_CONTROL)(&DataByte))->RequestToSend = 1;
+ WRITE_REGISTER_UCHAR(&SP_WRITE->ModemControl, DataByte);
+
+ return TRUE;
+}
+
+ULONG
+KdPortGetByte (
+ OUT PUCHAR Input
+ )
+
+/*++
+
+Routine Description:
+
+ This routine gets a byte from the serial port used by the kernel
+ debugger.
+
+ N.B. It is assumed that the IRQL has been raised to the highest
+ level, and necessary multiprocessor synchronization has been
+ performed before this routine is called.
+
+Arguments:
+
+ Input - Supplies a pointer to a variable that receives the input
+ data byte.
+
+Return Value:
+
+ CP_GET_SUCCESS is returned if a byte is successfully read from the
+ kernel debugger line.
+
+ CP_GET_ERROR is returned if an error is encountered during reading.
+
+ CP_GET_NODATA is returned if timeout occurs.
+
+--*/
+
+{
+ return HalpGetByte(Input, TRUE);
+}
+
+ULONG
+KdPortPollByte (
+ OUT PUCHAR Input
+ )
+
+/*++
+
+Routine Description:
+
+ This routine gets a byte from the serial port used by the kernel
+ debugger iff a byte is available.
+
+ N.B. It is assumed that the IRQL has been raised to the highest
+ level, and necessary multiprocessor synchronization has been
+ performed before this routine is called.
+
+Arguments:
+
+ Input - Supplies a pointer to a variable that receives the input
+ data byte.
+
+Return Value:
+
+ CP_GET_SUCCESS is returned if a byte is successfully read from the
+ kernel debugger line.
+
+ CP_GET_ERROR is returned if an error encountered during reading.
+
+ CP_GET_NODATA is returned if timeout occurs.
+
+--*/
+
+{
+
+ ULONG Status;
+
+ //
+ // Save port status, map the serial controller, get byte from the
+ // debugger port is one is avaliable, restore port status, unmap
+ // the serial controller, and return the operation status.
+ //
+
+ KdPortSave();
+ Status = HalpGetByte(Input, FALSE);
+ KdPortRestore();
+ return Status;
+}
+
+VOID
+KdPortPutByte (
+ IN UCHAR Output
+ )
+
+/*++
+
+Routine Description:
+
+ This routine puts a byte to the serial port used by the kernel debugger.
+
+ N.B. It is assumed that the IRQL has been raised to the highest level,
+ and necessary multiprocessor synchronization has been performed
+ before this routine is called.
+
+Arguments:
+
+ Output - Supplies the output data byte.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UCHAR DataByte;
+
+ if (KdUseModemControl) {
+ //
+ // Modem control, make sure DSR, CTS and CD are all set before
+ // sending any data.
+ //
+
+ for (; ;) {
+ DataByte = READ_REGISTER_UCHAR(&SP_READ->ModemStatus);
+ if ( ((PSP_MODEM_STATUS)&DataByte)->ClearToSend &&
+ ((PSP_MODEM_STATUS)&DataByte)->DataSetReady &&
+ ((PSP_MODEM_STATUS)&DataByte)->ReceiveDetect ) {
+ break;
+ }
+
+ KdReadLsr(FALSE);
+ }
+ }
+
+ //
+ // Wait for transmit ready.
+ //
+
+ while (KdReadLsr(FALSE).TransmitHoldingEmpty == 0 );
+
+ //
+ // Wait for data set ready.
+ //
+
+// do {
+// LsrByte = READ_REGISTER_UCHAR(&SP_READ->ModemStatus);
+// } while (((PSP_MODEM_STATUS)(&LsrByte))->DataSetReady == 0);
+
+ //
+ // Transmit data.
+ //
+
+ WRITE_REGISTER_UCHAR(&SP_WRITE->TransmitBuffer, Output);
+ return;
+}
+
+VOID
+KdPortRestore (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine restores the state of the serial port after the kernel
+ debugger has been active.
+
+ N.B. This routine performs no function on the Jazz system.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ return;
+}
+
+VOID
+KdPortSave (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine saves the state of the serial port and initializes the port
+ for use by the kernel debugger.
+
+ N.B. This routine performs no function on the Jazz system.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ return;
+}
+
+SP_LINE_STATUS
+KdReadLsr (
+ IN BOOLEAN WaitReason
+ )
+
+/*++
+
+Routine Description:
+
+ Returns current line status.
+
+ If status which is being waited for is ready, then the function
+ checks the current modem status and causes a possible display update
+ of the current statuses.
+
+Arguments:
+
+ WaitReason - Suuplies a boolean value that determines whether the line
+ status is required for a receive or transmit.
+
+Return Value:
+
+ The current line status is returned as the function value.
+
+--*/
+
+{
+
+ static UCHAR RingFlag = 0;
+ UCHAR DataLsr, DataMsr;
+
+ //
+ // Get the line status for a recevie or a transmit.
+ //
+
+ DataLsr = READ_REGISTER_UCHAR(&SP_READ->LineStatus);
+ if (WaitReason) {
+
+ //
+ // Get line status for receive data.
+ //
+
+ if (((PSP_LINE_STATUS)&DataLsr)->DataReady) {
+ return *((PSP_LINE_STATUS)&DataLsr);
+ }
+
+ } else {
+
+ //
+ // Get line status for transmit empty.
+ //
+
+ if (((PSP_LINE_STATUS)&DataLsr)->TransmitEmpty) {
+ return *((PSP_LINE_STATUS)&DataLsr);
+ }
+ }
+
+ DataMsr = READ_REGISTER_UCHAR(&SP_READ->ModemStatus);
+ RingFlag |= ((PSP_MODEM_STATUS)&DataMsr)->RingIndicator ? 1 : 2;
+ if (RingFlag == 3) {
+
+ //
+ // The ring indicate line has toggled, use modem control from
+ // now on.
+ //
+
+ KdUseModemControl = TRUE;
+ }
+
+ return *((PSP_LINE_STATUS) &DataLsr);
+}
+
+VOID
+HalpGetDivisorFromBaud(
+ IN ULONG ClockRate,
+ IN LONG DesiredBaud,
+ OUT PSHORT AppropriateDivisor
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will determine a divisor based on an unvalidated
+ baud rate.
+
+Arguments:
+
+ ClockRate - The clock input to the controller.
+
+ DesiredBaud - The baud rate for whose divisor we seek.
+
+ AppropriateDivisor - Given that the DesiredBaud is valid, the
+ SHORT pointed to by this parameter will be set to the appropriate
+ value. If the requested baud rate is unsupportable on the machine
+ return a divisor appropriate for 19200.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ SHORT calculatedDivisor;
+ ULONG denominator;
+ ULONG remainder;
+
+ //
+ // Allow up to a 1 percent error
+ //
+
+ ULONG maxRemain18 = 18432;
+ ULONG maxRemain30 = 30720;
+ ULONG maxRemain42 = 42336;
+ ULONG maxRemain80 = 80000;
+ ULONG maxRemain;
+
+ //
+ // Reject any non-positive bauds.
+ //
+
+ denominator = DesiredBaud*(ULONG)16;
+
+ if (DesiredBaud <= 0) {
+
+ *AppropriateDivisor = -1;
+
+ } else if ((LONG)denominator < DesiredBaud) {
+
+ //
+ // If the desired baud was so huge that it cause the denominator
+ // calculation to wrap, don't support it.
+ //
+
+ *AppropriateDivisor = -1;
+
+ } else {
+
+ if (ClockRate == 1843200) {
+ maxRemain = maxRemain18;
+ } else if (ClockRate == 3072000) {
+ maxRemain = maxRemain30;
+ } else if (ClockRate == 4233600) {
+ maxRemain = maxRemain42;
+ } else {
+ maxRemain = maxRemain80;
+ }
+
+ calculatedDivisor = (SHORT)(ClockRate / denominator);
+ remainder = ClockRate % denominator;
+
+ //
+ // Round up.
+ //
+
+ if (((remainder*2) > ClockRate) && (DesiredBaud != 110)) {
+
+ calculatedDivisor++;
+ }
+
+
+ //
+ // Only let the remainder calculations effect us if
+ // the baud rate is > 9600.
+ //
+
+ if (DesiredBaud >= 9600) {
+
+ //
+ // If the remainder is less than the maximum remainder (wrt
+ // the ClockRate) or the remainder + the maximum remainder is
+ // greater than or equal to the ClockRate then assume that the
+ // baud is ok.
+ //
+
+ if ((remainder >= maxRemain) && ((remainder+maxRemain) < ClockRate)) {
+ calculatedDivisor = -1;
+ }
+
+ }
+
+ //
+ // Don't support a baud that causes the denominator to
+ // be larger than the clock.
+ //
+
+ if (denominator > ClockRate) {
+
+ calculatedDivisor = -1;
+
+ }
+
+ //
+ // Ok, Now do some special casing so that things can actually continue
+ // working on all platforms.
+ //
+
+ if (ClockRate == 1843200) {
+
+ if (DesiredBaud == 56000) {
+ calculatedDivisor = 2;
+ }
+
+ } else if (ClockRate == 3072000) {
+
+ if (DesiredBaud == 14400) {
+ calculatedDivisor = 13;
+ }
+
+ } else if (ClockRate == 4233600) {
+
+ if (DesiredBaud == 9600) {
+ calculatedDivisor = 28;
+ } else if (DesiredBaud == 14400) {
+ calculatedDivisor = 18;
+ } else if (DesiredBaud == 19200) {
+ calculatedDivisor = 14;
+ } else if (DesiredBaud == 38400) {
+ calculatedDivisor = 7;
+ } else if (DesiredBaud == 56000) {
+ calculatedDivisor = 5;
+ }
+
+ } else if (ClockRate == 8000000) {
+
+ if (DesiredBaud == 14400) {
+ calculatedDivisor = 35;
+ } else if (DesiredBaud == 56000) {
+ calculatedDivisor = 9;
+ }
+
+ }
+
+ *AppropriateDivisor = calculatedDivisor;
+
+ }
+
+
+ if (*AppropriateDivisor == -1) {
+
+ HalpGetDivisorFromBaud(
+ ClockRate,
+ 19200,
+ AppropriateDivisor
+ );
+
+ }
+
+
+}
+
+
diff --git a/private/ntos/nthals/haldti/mips/jxreturn.c b/private/ntos/nthals/haldti/mips/jxreturn.c
new file mode 100644
index 000000000..3ca52b325
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/jxreturn.c
@@ -0,0 +1,89 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ jxreturn.c
+
+Abstract:
+
+ This module implements the HAL return to firmware function.
+
+Author:
+
+ David N. Cutler (davec) 21-Aug-1991
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "eisa.h"
+
+VOID
+HalReturnToFirmware(
+ IN FIRMWARE_REENTRY Routine
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns control to the specified firmware routine.
+ In most cases it generates a soft reset by asserting the reset line
+ trough the keyboard controller.
+ The Keyboard controller is mapped using the same virtual address
+ and the same fixed entry as the DMA.
+
+Arguments:
+
+ Routine - Supplies a value indicating which firmware routine to invoke.
+
+Return Value:
+
+ Does not return.
+
+--*/
+
+{
+ KIRQL OldIrql;
+
+ //
+ // Disable Interrupts.
+ //
+ KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+
+ //
+ // Case on the type of return.
+ //
+
+ switch (Routine) {
+ case HalHaltRoutine:
+
+ //
+ // Hang looping.
+ //
+ for (;;) {
+ }
+
+ case HalPowerDownRoutine:
+ case HalRestartRoutine:
+ case HalRebootRoutine:
+ case HalInteractiveModeRoutine:
+
+ if (HalpResetDisplayParameters != NULL) {
+ (HalpResetDisplayParameters)(80,25);
+ }
+
+ HalpResetX86DisplayAdapter();
+ ArcReboot();
+ for (;;) {
+ }
+
+ default:
+ KdPrint(("HalReturnToFirmware invalid argument\n"));
+ KeLowerIrql(OldIrql);
+ DbgBreakPoint();
+ }
+}
diff --git a/private/ntos/nthals/haldti/mips/jxsysint.c b/private/ntos/nthals/haldti/mips/jxsysint.c
new file mode 100644
index 000000000..af60aded5
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/jxsysint.c
@@ -0,0 +1,252 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ jxsysint.c
+
+Abstract:
+
+ This module implements the HAL enable/disable system interrupt, and
+ request interprocessor interrupt routines for a MIPS R3000 or R4000
+ Jazz system.
+
+Author:
+
+ David N. Cutler (davec) 6-May-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "halp.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 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);
+ }
+
+ //
+ // 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 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);
+ }
+
+ //
+ // Lower IRQL to the previous level.
+ //
+
+ KeLowerIrql(OldIrql);
+ return TRUE;
+}
+
+ULONG
+HalGetInterruptVector(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG BusInterruptLevel,
+ IN ULONG BusInterruptVector,
+ OUT PKIRQL Irql,
+ OUT PKAFFINITY Affinity
+ )
+
+/*++
+
+Routine Description:
+
+ This functionr returns the system interrupt vector and IRQL level
+ corresponding to the specified bus interrupt level and/or vector. The
+ system interrupt vector and IRQL are suitable for use in a subsequent call
+ to KeInitializeInterrupt.
+
+Arguments:
+
+ InterfaceType - Supplies the type of bus which the vector is for.
+
+ BusNumber - Supplies the bus number for the device.
+
+ BusInterruptLevel - Supplies the bus specific interrupt level.
+
+ BusInterruptVector - Supplies the bus specific interrupt vector.
+
+ Irql - Returns the system request priority.
+
+ Affinity - Returns the affinity for the requested vector
+
+Return Value:
+
+ Returns the system interrupt vector corresponding to the specified device.
+
+--*/
+
+{
+ *Affinity = 1;
+
+ if (InterfaceType != Isa &&
+ InterfaceType != Eisa &&
+ InterfaceType != Internal) {
+
+ //
+ // Not on this system return nothing.
+ //
+
+ *Affinity = 0;
+ *Irql = 0;
+ return(0);
+
+ }
+
+ //
+ // Jazz only has one I/O bus which is an EISA, so the bus number and the
+ // bus interrupt vector are unused.
+ //
+ // The IRQL level is always equal to the EISA level.
+ //
+
+ *Irql = EISA_DEVICE_LEVEL;
+
+ //
+ // Bus interrupt level 2 is actually mapped to bus level 9 in the Eisa
+ // hardware.
+ //
+
+ if (BusInterruptLevel == 2) {
+ BusInterruptLevel = 9;
+ }
+
+ //
+ // The vector is equal to the specified bus level plus the EISA_VECTOR.
+ //
+
+ return(BusInterruptLevel + EISA_VECTORS);
+
+}
+
+VOID
+HalRequestIpi (
+ IN ULONG Mask
+ )
+
+/*++
+
+Routine Description:
+
+ This routine requests an interprocessor interrupt on a set of processors.
+
+Arguments:
+
+ Mask - Supplies the set of processors that are sent an interprocessor
+ interrupt.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ return;
+}
diff --git a/private/ntos/nthals/haldti/mips/jxtime.c b/private/ntos/nthals/haldti/mips/jxtime.c
new file mode 100644
index 000000000..25c825f89
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/jxtime.c
@@ -0,0 +1,278 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ jxtime.c
+
+Abstract:
+
+ This module implements the HAL set/query realtime clock routines for
+ a MIPS R3000 or R4000 Jazz system.
+
+Author:
+
+ David N. Cutler (davec) 5-May-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "jazzrtc.h"
+#include "eisa.h"
+
+#define BCDToBinary(D) (10 * (((D) & 0xf0) >>4 ) + ((D) & 0x0f))
+#define BinaryToBCD(B) ((((B) & 0xff) / 10) << 4 ) | (((B) & 0xff) % 10)
+
+//
+// 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 is required to provide any synchronization necessary
+ to query the realtime clock information.
+
+Arguments:
+
+ TimeFields - Supplies a pointer to a time structure that receives
+ the realtime clock information.
+
+Return Value:
+
+ If the power to the realtime clock has not failed, then the time
+ values are read from the realtime clock and a value of TRUE is
+ returned. Otherwise, a value of FALSE is returned.
+
+--*/
+
+{
+
+ UCHAR DataByte;
+ KIRQL 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.
+ //
+
+ KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+ 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 = 1900 + (CSHORT)BCDToBinary(HalpReadClockRegister(RTC_YEAR));
+ if (TimeFields->Year < 1992)
+ TimeFields->Year += 100;
+ TimeFields->Month = (CSHORT)BCDToBinary(HalpReadClockRegister(RTC_MONTH));
+ TimeFields->Day = (CSHORT)BCDToBinary(HalpReadClockRegister(RTC_DAY_OF_MONTH));
+ TimeFields->Weekday = (CSHORT)BCDToBinary(HalpReadClockRegister(RTC_DAY_OF_WEEK)) - 1;
+ TimeFields->Hour = (CSHORT)BCDToBinary(HalpReadClockRegister(RTC_HOUR));
+ TimeFields->Minute = (CSHORT)BCDToBinary(HalpReadClockRegister(RTC_MINUTE));
+ TimeFields->Second = (CSHORT)BCDToBinary(HalpReadClockRegister(RTC_SECOND));
+ TimeFields->Milliseconds = 0;
+ KeLowerIrql(OldIrql);
+ return TRUE;
+
+ } else {
+ KeLowerIrql(OldIrql);
+ return FALSE;
+ }
+}
+
+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 set the realtime clock information.
+
+Arguments:
+
+ TimeFields - Supplies a pointer to a time structure that specifies the
+ realtime clock information.
+
+Return Value:
+
+ If the power to the realtime clock has not failed, then the time
+ values are written to the realtime clock and a value of TRUE is
+ returned. Otherwise, a value of FALSE is returned.
+
+--*/
+
+{
+
+ UCHAR DataByte;
+ KIRQL OldIrql;
+
+ //
+ // 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))->DayLightSavingsEnable = 1;
+ ((PRTC_CONTROL_REGISTER_B)(&DataByte))->HoursFormat = 1;
+ ((PRTC_CONTROL_REGISTER_B)(&DataByte))->DataMode = 0;
+ ((PRTC_CONTROL_REGISTER_B)(&DataByte))->SetTime = 1;
+ HalpWriteClockRegister(RTC_CONTROL_REGISTERB, DataByte);
+
+ //
+ // Write the realtime clock values.
+ //
+
+ HalpWriteClockRegister(RTC_YEAR, (UCHAR)(BinaryToBCD(TimeFields->Year - 1900)));
+ HalpWriteClockRegister(RTC_MONTH, (UCHAR)BinaryToBCD(TimeFields->Month));
+ HalpWriteClockRegister(RTC_DAY_OF_MONTH, (UCHAR)BinaryToBCD(TimeFields->Day));
+ HalpWriteClockRegister(RTC_DAY_OF_WEEK, (UCHAR)(BinaryToBCD(TimeFields->Weekday + 1)));
+ HalpWriteClockRegister(RTC_HOUR, (UCHAR)BinaryToBCD(TimeFields->Hour));
+ HalpWriteClockRegister(RTC_MINUTE, (UCHAR)BinaryToBCD(TimeFields->Minute));
+ HalpWriteClockRegister(RTC_SECOND, (UCHAR)BinaryToBCD(TimeFields->Second));
+
+ //
+ // Set the realtime clock control to update the time.
+ //
+
+ ((PRTC_CONTROL_REGISTER_B)(&DataByte))->SetTime = 0;
+ 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.
+
+--*/
+
+{
+
+ //
+ // Insert the realtime clock register number, and write the value back
+ // to the EISA NMI enable register. This selects the realtime clock register
+ // that is read. Note this is a write only register and the EISA NMI
+ // is always enabled.
+ //
+
+ WRITE_REGISTER_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->NmiEnable,
+ Register);
+
+ //
+ // Read the realtime clock register value.
+ //
+
+ return READ_REGISTER_UCHAR((PUCHAR)HalpRealTimeClockBase);
+}
+
+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:
+
+ The value of the register is returned as the function value.
+
+--*/
+
+{
+
+ //
+ // Insert the realtime clock register number, and write the value back
+ // to the EISA NMI enable register. This selects the realtime clock
+ // register that is written. Note this is a write only register and
+ // the EISA NMI is always enabled.
+ //
+
+ WRITE_REGISTER_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->NmiEnable,
+ Register);
+
+ //
+ // Write the realtime clock register value.
+ //
+
+ WRITE_REGISTER_UCHAR((PUCHAR)HalpRealTimeClockBase, Value);
+ return;
+}
diff --git a/private/ntos/nthals/haldti/mips/jxusage.c b/private/ntos/nthals/haldti/mips/jxusage.c
new file mode 100644
index 000000000..0c1d01efc
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/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 JAZZ 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/haldti/mips/x4clock.s b/private/ntos/nthals/haldti/mips/x4clock.s
new file mode 100644
index 000000000..9b20f0e03
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/x4clock.s
@@ -0,0 +1,210 @@
+#if defined(R4000)
+
+// TITLE("Interval and Profile Clock Interrupts")
+//++
+//
+// Copyright (c) 1991 Microsoft Corporation
+//
+// Module Name:
+//
+// x4clock.s
+//
+// Abstract:
+//
+// This module implements the code necessary to field and process the
+// interval and profile clock interrupts on a MIPS R4000 system.
+//
+// Author:
+//
+// David N. Cutler (davec) 26-Apr-1991
+//
+// Environment:
+//
+// Kernel mode only.
+//
+// Revision History:
+//
+//--
+
+#include "halmips.h"
+
+ SBTTL("System Clock Interrupt")
+//++
+//
+// Routine Description:
+//
+// This routine is entered as the result of an interrupt generated by
+// the interval timer. Its function is to acknowledge the interrupt and
+// transfer control to the standard system routine to update the system
+// time and the execution time of the current thread and process.
+//
+// Arguments:
+//
+// s8 - Supplies a pointer to a trap frame.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ .struct 0
+CiArgs: .space 4 * 4 // saved arguments
+ .space 3 * 4 // fill
+CiRa: .space 4 // saved return address
+CiFrameLength: //
+
+ NESTED_ENTRY(HalpClockInterrupt, CiFrameLength, zero)
+
+ subu sp,sp,CiFrameLength // allocate stack frame
+ sw ra,CiRa(sp) // save return address
+
+ PROLOGUE_END
+
+ move a0,s8 // set address of trap frame
+ lw a1,HalpCurrentTimeIncrement // Get current time increment
+ jal KeUpdateSystemTime // update system time
+ lw t0,HalpNextTimeIncrement // Get NextTimeIncrement
+ sw t0,HalpCurrentTimeIncrement // Set CurrentTimeIncrement to NextTimeIncrement
+ lw a0,HalpNextIntervalCount // Get Next Interval Count. If 0, then no change required
+ beq zero,a0,5f // See if time increment is to be changed
+ jal HalpProgramIntervalTimer // Program timer with new interval count value
+ lw t0,HalpNewTimeIncrement // Get HalpNewTimeIncrement
+ sw t0,HalpNextTimeIncrement // Set HalpNextTimeIncrement to HalpNewTimeIncrement
+ sw zero,HalpNextIntervalCount // Set HalpNextIntervalCount to 0
+5:
+ lw t0,KdDebuggerEnabled // check if debugger enabled
+ lbu t0,0(t0) //
+ beq zero,t0,10f // if eq, debugger not enabled
+ jal KdPollBreakIn // check if breakin is requested
+ beq zero,v0,10f // if eq, no breakin requested
+ li a0,DBG_STATUS_CONTROL_C // break in and send
+ jal DbgBreakPointWithStatus // status to debugger
+10: lw ra,CiRa(sp) // restore return address
+ addu sp,sp,CiFrameLength // deallocate stack frame
+ j ra // return
+
+ .end HalpClockInterrupt
+
+ SBTTL("Profile Clock Interrupt")
+//++
+//
+// Routine Description:
+//
+// This routine is entered as the result of an interrupt generated by the
+// profile clock. Its function is to acknowledge the profile interrupt,
+// compute the next compare value, update the performance counter, and
+// transfer control to the standard system routine to process any active
+// profiles.
+//
+// Arguments:
+//
+// s8 - Supplies a pointer to a trap frame.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalpProfileInterrupt)
+
+ .set noreorder
+ .set noat
+ mfc0 t1,count // get current count value
+ mfc0 t0,compare // get current comparison value
+ addu t1,t1,8 // factor in lost cycles
+ subu t1,t1,t0 // compute initial count value
+ mtc0 t0,compare // dismiss interrupt
+ mtc0 t1,count // set new count register value
+ .set at
+ .set reorder
+
+ la t1,HalpPerformanceCounter // get performance counter address
+ lw t2,LiLowPart(t1) // get low part of performance count
+ lw t3,LiHighPart(t1) // get high part of performance count
+ addu t2,t2,t0 // update low part of performance count
+ sw t2,LiLowPart(t1) // store low part of performance count
+ sltu t4,t2,t0 // generate carry into high part
+ addu t3,t3,t4 // update high part of performance count
+ sw t3,LiHighPart(t1) // store high part of performance count
+ move a0,s8 // set address of trap frame
+ j KeProfileInterrupt // process profile entries
+
+ .end HalpProfileInterrupt
+
+ SBTTL("Read Count Register")
+//++
+//
+// ULONG
+// HalpReadCountRegister (
+// VOID
+// );
+//
+// Routine Description:
+//
+// This routine reads the current value of the count register and
+// returns the value.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// Current value of the count register.
+//
+//--
+
+ LEAF_ENTRY(HalpReadCountRegister)
+
+ .set noreorder
+ .set noat
+ mfc0 v0,count // get count register value
+ .set at
+ .set reorder
+
+ j ra // return
+
+ .end HalpReadCountRegister
+
+ SBTTL("Write Compare Register And Clear")
+//++
+//
+// ULONG
+// HalpWriteCompareRegisterAndClear (
+// IN ULONG Value
+// );
+//
+// Routine Description:
+//
+// This routine reads the current value of the count register, writes
+// the value of the compare register, clears the count register, and
+// returns the previous value of the count register.
+//
+// Arguments:
+//
+// Value - Supplies the value written to the compare register.
+//
+// Return Value:
+//
+// Previous value of the count register.
+//
+//--
+
+ LEAF_ENTRY(HalpWriteCompareRegisterAndClear)
+
+ .set noreorder
+ .set noat
+ mfc0 v0,count // get count register value
+ mtc0 a0,compare // set compare register value
+ li t0,7 // set lost cycle count
+ mtc0 t0,count // set count register to zero
+ .set at
+ .set reorder
+
+ j ra // return
+
+ .end HalpWriteCompareRegisterAndClear
+
+#endif
diff --git a/private/ntos/nthals/haldti/mips/x86bios.c b/private/ntos/nthals/haldti/mips/x86bios.c
new file mode 100644
index 000000000..c31a8baf5
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/x86bios.c
@@ -0,0 +1,262 @@
+/*++
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ x86bios.c
+
+Abstract:
+
+
+ This module implements the platform specific interface between a device
+ driver and the execution of x86 ROM bios code for the device.
+
+Author:
+
+ David N. Cutler (davec) 17-Jun-1994
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+
+typedef struct FIRMWARE_INT_ARGUMENTS {
+ ULONG pEAX;
+ ULONG pEBX;
+ ULONG pECX;
+ ULONG pEDX;
+ ULONG pESI;
+ ULONG pEDI;
+ ULONG pEBP;
+ USHORT pES;
+ USHORT pDS;
+ USHORT pFlags;
+} FIRMWARE_INT_ARGUMENTS, *PFIRMWARE_INT_ARGUMENTS;
+
+ULONG HalpX86BiosInitialized = FALSE;
+ULONG HalpEnableInt10Calls = FALSE;
+ULONG HalpUseFirmwareX86Emulator = FALSE;
+
+typedef
+VOID
+(*PVENDOR_EXECUTE_INT) (
+ IN USHORT Type,
+ IN PFIRMWARE_INT_ARGUMENTS Context
+ );
+
+PVENDOR_EXECUTE_INT VendorX86ExecuteInt;
+
+VOID HalpInitializeX86DisplayAdapter()
+
+{
+ PSYSTEM_PARAMETER_BLOCK SystemParameterBlock = (PSYSTEM_PARAMETER_BLOCK)(0x80001000);
+
+ //
+ // If EISA I/O Ports or EISA Memory could not be mapped, then leave the
+ // X86 BIOS Emulator disabled.
+ //
+
+ if (HalpEisaControlBase == NULL || HalpEisaMemoryBase == NULL) {
+
+// DbgPrint("X86 BIOS Emulator Disabled\n");
+
+ return;
+ }
+
+ //
+ // If Firmware level X86 Bios Emulator exists, then use that instead of the
+ // one built into the HAL.
+ //
+
+ if ((SystemParameterBlock->VendorVectorLength/4) >= 34) {
+
+ VendorX86ExecuteInt =
+ *(PVENDOR_EXECUTE_INT *)((ULONG)(SystemParameterBlock->VendorVector) + 34*4);
+
+ if (VendorX86ExecuteInt != NULL) {
+ HalpX86BiosInitialized = TRUE;
+ HalpUseFirmwareX86Emulator = TRUE;
+ HalpEnableInt10Calls = TRUE;
+
+// DbgPrint("Firmware X86 BIOS Emulator Enabled\n");
+// DbgPrint("INT 10 Calls Enabled\n");
+
+ return;
+ }
+ }
+
+// DbgPrint("HAL X86 BIOS Emulator Enabled\n");
+
+ x86BiosInitializeBios(HalpEisaControlBase, HalpEisaMemoryBase);
+
+ HalpX86BiosInitialized = TRUE;
+
+ //
+ // Attempt to initialize the Display Adapter by executing the Display Adapters
+ // initialization code in its BIOS. The standard for PC video adapters is for
+ // the BIOS to reside at 0xC000:0000 on the ISA bus.
+ //
+
+// DbgPrint("X86BiosInitializeAdapter(0xc0000)\n");
+
+ if (x86BiosInitializeAdapter(0xc0000, NULL, NULL, NULL) != XM_SUCCESS) {
+ HalpEnableInt10Calls = FALSE;
+
+// DbgPrint("INT 10 Calls Disabled\n");
+
+ return;
+ }
+
+ HalpEnableInt10Calls = TRUE;
+
+// DbgPrint("INT 10 Calls Enabled\n");
+}
+
+VOID HalpResetX86DisplayAdapter()
+
+{
+ XM86_CONTEXT Context;
+
+ //
+ // Make INT 10 call to initialize 80x25 color text mode.
+ //
+
+ Context.Eax = 0x0003; // Function 0, Mode 3
+ Context.Ebx = 0;
+ Context.Ecx = 0;
+ Context.Edx = 0;
+ Context.Esi = 0;
+ Context.Edi = 0;
+ Context.Ebp = 0;
+
+ HalCallBios(0x10,
+ &Context.Eax,
+ &Context.Ebx,
+ &Context.Ecx,
+ &Context.Edx,
+ &Context.Esi,
+ &Context.Edi,
+ &Context.Ebp);
+}
+
+
+BOOLEAN
+HalCallBios (
+ IN ULONG BiosCommand,
+ IN OUT PULONG Eax,
+ IN OUT PULONG Ebx,
+ IN OUT PULONG Ecx,
+ IN OUT PULONG Edx,
+ IN OUT PULONG Esi,
+ IN OUT PULONG Edi,
+ IN OUT PULONG Ebp
+ )
+
+/*++
+
+Routine Description:
+
+ This function provides the platform specific interface between a device
+ driver and the execution of the x86 ROM bios code for the specified ROM
+ bios command.
+
+Arguments:
+
+ BiosCommand - Supplies the ROM bios command to be emulated.
+
+ Eax to Ebp - Supplies the x86 emulation context.
+
+Return Value:
+
+ A value of TRUE is returned if the specified function is executed.
+ Otherwise, a value of FALSE is returned.
+
+--*/
+
+{
+ FIRMWARE_INT_ARGUMENTS Arguments;
+ XM86_CONTEXT Context;
+
+
+ //
+ // If the X86 BIOS Emulator has not been initialized then fail all INT calls.
+ //
+
+ if (HalpX86BiosInitialized == FALSE) {
+ return(FALSE);
+ }
+
+ //
+ // If the Video Adapter initialization failed, then we can not make INT 10 calls.
+ //
+
+ if (BiosCommand == 0x10 && HalpEnableInt10Calls == FALSE) {
+ return(FALSE);
+ }
+
+// DbgPrint("HalCallBios(%02X,%04X,%04X,%04X,%04X,%04X,%04X,%04X)\n",BiosCommand,*Eax,*Ebx,*Ecx,*Edx,*Esi,*Edi,*Ebp);
+
+ if (HalpUseFirmwareX86Emulator == TRUE) {
+
+ //
+ // Make private vector call to the emulator in the firmware.
+ //
+
+ Arguments.pEAX = *Eax;
+ Arguments.pEBX = *Ebx;
+ Arguments.pECX = *Ecx;
+ Arguments.pEDX = *Edx;
+ Arguments.pESI = *Esi;
+ Arguments.pEDI = *Edi;
+ Arguments.pEBP = *Ebp;
+ Arguments.pES = 0;
+ Arguments.pDS = 0;
+ Arguments.pFlags = 0;
+
+ VendorX86ExecuteInt((USHORT)BiosCommand,&Arguments);
+
+ *Eax = Arguments.pEAX;
+ *Ebx = Arguments.pEBX;
+ *Ecx = Arguments.pECX;
+ *Edx = Arguments.pEDX;
+ *Esi = Arguments.pESI;
+ *Edi = Arguments.pEDI;
+ *Ebp = Arguments.pEBP;
+
+ }
+ else {
+
+ //
+ // Make call to emulator build into HAL
+ //
+
+ Context.Eax = *Eax;
+ Context.Ebx = *Ebx;
+ Context.Ecx = *Ecx;
+ Context.Edx = *Edx;
+ Context.Esi = *Esi;
+ Context.Edi = *Edi;
+ Context.Ebp = *Ebp;
+
+ if (x86BiosExecuteInterrupt((UCHAR)BiosCommand, &Context, NULL, NULL) != XM_SUCCESS) {
+ return FALSE;
+ }
+
+ *Eax = Context.Eax;
+ *Ebx = Context.Ebx;
+ *Ecx = Context.Ecx;
+ *Edx = Context.Edx;
+ *Esi = Context.Esi;
+ *Edi = Context.Edi;
+ *Ebp = Context.Ebp;
+
+ }
+
+ return TRUE;
+}
diff --git a/private/ntos/nthals/haldti/mips/x86bios.h b/private/ntos/nthals/haldti/mips/x86bios.h
new file mode 100644
index 000000000..c52a96fea
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/x86bios.h
@@ -0,0 +1,11 @@
+//
+// This file simply includes the main code from the haltyne directory after
+// undef'ed NT_UP if necessary.
+//
+
+
+#if defined(NT_UP)
+#undef NT_UP
+#endif
+
+#include "..\haltyne\mips\x86bios.h"
diff --git a/private/ntos/nthals/haldti/mips/x86lator.c b/private/ntos/nthals/haldti/mips/x86lator.c
new file mode 100644
index 000000000..b1e36cb72
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/x86lator.c
@@ -0,0 +1,11 @@
+//
+// This file simply includes the main code from the haltyne directory after
+// undef'ed NT_UP if necessary.
+//
+
+
+#if defined(NT_UP)
+#undef NT_UP
+#endif
+
+#include "..\haltyne\mips\x86lator.c"
diff --git a/private/ntos/nthals/haldti/mips/xxcalstl.c b/private/ntos/nthals/haldti/mips/xxcalstl.c
new file mode 100644
index 000000000..d30177228
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/xxcalstl.c
@@ -0,0 +1,291 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ xxcalstl.c
+
+Abstract:
+
+
+ This module implements the calibration of the stall execution HAL
+ service, computes the count rate for the profile clock, and connects
+ the clock and profile interrupts for a MIPS R3000 or R4000 system.
+
+Author:
+
+ David N. Cutler (davec) 26-Apr-1991
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "eisa.h"
+
+//
+// Define global data used to calibrate and stall processor execution.
+//
+
+ULONG HalpProfileCountRate;
+ULONG volatile HalpStallEnd;
+ULONG volatile HalpStallStart;
+
+BOOLEAN
+HalpCalibrateStall (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function calibrates the stall execution HAL service and connects
+ the clock and profile interrupts to the appropriate NT service routines.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A value of TRUE is returned if the calibration is successfully
+ completed. Otherwise a value of FALSE is returned.
+
+--*/
+
+{
+
+ ULONG Index;
+ KIRQL OldIrql;
+ PKPRCB Prcb;
+
+ //
+ // Start the system clock to interrupt at the MAXIMUM_INCREMENT interval.
+ //
+ // N.B. MAXIMUM_INCREMENT is in 100ns units.
+ //
+
+ HalSetTimeIncrement(MAXIMUM_INCREMENT);
+ HalpProgramIntervalTimer(HalpNextIntervalCount);
+ HalpEnableEisaInterrupt(CLOCK2_LEVEL,Latched); /* Enable Timer1,Counter0 interrupt */
+
+ //
+ // Use a range of scale factors from 50ns down to 10ns assuming a
+ // five instruction stall loop.
+ //
+
+ for (Index = 50; Index > 0; Index -= 10) {
+
+ //
+ // Disable all interrupts and establish calibration parameters.
+ //
+
+ KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+
+ //
+ // Set the scale factor, stall count, starting stall count, and
+ // ending stall count values.
+ //
+
+ PCR->StallScaleFactor = 1000 / (Index * 5);
+ PCR->StallExecutionCount = 0;
+ HalpStallStart = 0;
+ HalpStallEnd = 0;
+
+ //
+ // Enable interrupts and stall execution.
+ //
+
+ KeLowerIrql(OldIrql);
+
+ //
+ // Stall execution for (MAXIMUM_INCREMENT / 10) * 4 us.
+ //
+
+ KeStallExecutionProcessor((MAXIMUM_INCREMENT / 10) * 4);
+
+ //
+ // If both the starting and ending stall counts have been captured,
+ // then break out of loop.
+ //
+
+ if ((HalpStallStart != 0) && (HalpStallEnd != 0)) {
+ break;
+ }
+
+ }
+
+ //
+ // Compute the profile interrupt rate.
+ //
+
+#if defined(R3000)
+
+ HalpProfileCountRate = (1000 * 1000 * 10) / MAXIMUM_INCREMENT;
+
+#endif
+
+#if defined(R4000)
+
+ HalpProfileCountRate =
+ HalpProfileCountRate * ((1000 * 1000 * 10) / MAXIMUM_INCREMENT);
+
+#endif
+
+ //
+ // Compute the stall execution scale factor.
+ //
+
+ PCR->StallScaleFactor = (HalpStallEnd - HalpStallStart +
+ ((MAXIMUM_INCREMENT / 10) - 1)) / (MAXIMUM_INCREMENT / 10);
+
+ if (PCR->StallScaleFactor <= 0) {
+ PCR->StallScaleFactor = 1;
+ }
+
+ //
+ // Get the address of the processor control block for the current
+ // processor.
+ //
+
+ Prcb = PCR->Prcb;
+
+ //
+ // Connect the real clock interrupt routine.
+ //
+
+ PCR->InterruptRoutine[CLOCK2_LEVEL] = HalpClockInterrupt;
+
+ //
+ // Write the compare register and clear the count register, and
+ // connect the profile interrupt.
+ //
+
+#if defined(R4000)
+
+ HalpWriteCompareRegisterAndClear(DEFAULT_PROFILE_COUNT);
+ PCR->InterruptRoutine[PROFILE_LEVEL] = HalpProfileInterrupt;
+
+#endif
+
+ return TRUE;
+}
+
+VOID
+KeStallExecutionProcessor (
+ IN ULONG MicroSeconds
+ )
+
+/*++
+
+Routine Description:
+
+ This function stalls execution of the current processor for the specified
+ number of microseconds.
+
+Arguments:
+
+ MicroSeconds - Supplies the number of microseconds that execution is to
+ be stalled.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG Index;
+
+ //
+ // Use the stall scale factor to determine the number of iterations
+ // the wait loop must be executed to stall the processor for the
+ // specified number of microseconds.
+ //
+
+ Index = MicroSeconds * PCR->StallScaleFactor;
+ do {
+ PCR->StallExecutionCount += 1;
+ Index -= 1;
+ } while (Index > 0);
+
+ return;
+}
+
+VOID
+HalpStallInterrupt (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function serves as the stall calibration interrupt service
+ routine. It is executed in response to system clock interrupts
+ during the initialization of the HAL layer.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+// //
+// // Acknowledge the clock interrupt.
+// //
+//
+//#if defined(JAZZ)
+//
+// READ_REGISTER_ULONG(&DMA_CONTROL->IntervalTimer.Long);
+//
+//#endif
+
+ //
+ // If this is the very first interrupt, then wait for the second
+ // interrupt before starting the timing interval. Else, if this
+ // the second interrupt, then capture the starting stall count
+ // and clear the count register on R4000 processors. Else, if this
+ // is the third interrupt, then capture the ending stall count and
+ // the ending count register on R4000 processors. Else, if this is
+ // the fourth or subsequent interrupt, then simply dismiss it.
+ //
+
+ if ((HalpStallStart == 0) && (HalpStallEnd == 0)) {
+ HalpStallEnd = 1;
+
+ } else if ((HalpStallStart == 0) && (HalpStallEnd != 0)) {
+ HalpStallStart = PCR->StallExecutionCount;
+ HalpStallEnd = 0;
+
+#if defined(R4000)
+
+ HalpWriteCompareRegisterAndClear(0);
+
+#endif
+
+ } else if ((HalpStallStart != 0) && (HalpStallEnd == 0)) {
+ HalpStallEnd = PCR->StallExecutionCount;
+
+#if defined(R4000)
+
+ HalpProfileCountRate = HalpWriteCompareRegisterAndClear(0);
+
+#endif
+
+ }
+
+ return;
+}
diff --git a/private/ntos/nthals/haldti/mips/xxclock.c b/private/ntos/nthals/haldti/mips/xxclock.c
new file mode 100644
index 000000000..27a981d7b
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/xxclock.c
@@ -0,0 +1,171 @@
+/*++
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ xxclock.c
+
+Abstract:
+
+
+ This module implements the function necesssary to change the clock
+ interrupt rate.
+
+Author:
+
+ David N. Cutler (davec) 7-Feb-1994
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "eisa.h"
+
+//
+// Define clock count and time table.
+//
+
+typedef struct _COUNT_ENTRY {
+ ULONG Count;
+ ULONG Time;
+} COUNT_ENTRY, *PCOUNT_ENTRY;
+
+COUNT_ENTRY TimeTable[] = {
+ {1197, 10032},
+ {2394, 20064},
+ {3591, 30096},
+ {4767, 39952},
+ {5964, 49984},
+ {7161, 60016},
+ {8358, 70048},
+ {9555, 80080},
+ {10731, 89936},
+ {11928, 99968}
+ };
+
+//
+// Define global data used to communicate new clock rates to the clock
+// interrupt service routine.
+//
+
+ULONG HalpCurrentTimeIncrement;
+ULONG HalpNextIntervalCount;
+ULONG HalpNextTimeIncrement;
+ULONG HalpNewTimeIncrement;
+
+VOID
+HalpProgramIntervalTimer(
+ IN ULONG IntervalCount
+ )
+
+/*++
+
+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:
+
+ IntervalCount - Supplies cound value to be placed in the timer/counter.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ PEISA_CONTROL controlBase;
+ TIMER_CONTROL timerControl;
+
+ //
+ // Set the system clock timer to the correct mode.
+ //
+
+ timerControl.BcdMode = 0;
+ timerControl.Mode = TM_SQUARE_WAVE;
+ timerControl.SelectByte = SB_LSB_THEN_MSB;
+ timerControl.SelectCounter = SELECT_COUNTER_0;
+
+ controlBase = HalpEisaControlBase;
+
+ WRITE_REGISTER_UCHAR(&controlBase->CommandMode1, *((PUCHAR) &timerControl));
+
+ //
+ // Set the system clock timer to the correct frequency.
+ //
+
+ WRITE_REGISTER_UCHAR(&controlBase->Timer1, (UCHAR)IntervalCount);
+ WRITE_REGISTER_UCHAR(&controlBase->Timer1, (UCHAR)(IntervalCount >> 8));
+}
+
+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 Index;
+ 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);
+
+ //
+ // The new clock count value is selected from a precomputed table of
+ // count/time pairs. The values in the table were selected for their
+ // accuracy and closeness to the values of 1ms, 2ms, 3ms, etc. to 10ms.
+ //
+ // N.B. The NT executive guarantees that this function will never
+ // be called with the desired incrment less than the minimum
+ // increment or greater than the maximum increment.
+ //
+
+ for (Index = 0; Index < sizeof(TimeTable) / sizeof(COUNT_ENTRY); Index += 1) {
+ if (DesiredIncrement <= TimeTable[Index].Time) {
+ break;
+ }
+ }
+
+ if (DesiredIncrement < TimeTable[Index].Time) {
+ Index -= 1;
+ }
+
+ HalpNextIntervalCount = TimeTable[Index].Count;
+ HalpNewTimeIncrement = TimeTable[Index].Time;
+ KeLowerIrql(OldIrql);
+ return TimeTable[Index].Time;
+}
diff --git a/private/ntos/nthals/haldti/mips/xxidle.s b/private/ntos/nthals/haldti/mips/xxidle.s
new file mode 100644
index 000000000..d0cd9c78b
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/xxidle.s
@@ -0,0 +1,79 @@
+// TITLE("Processor Idle")
+//++
+//
+// Copyright (c) 1994 Microsoft Corporation
+//
+// Module Name:
+//
+// xxidle.s
+//
+// Abstract:
+//
+// This module implements system platform dependent power management
+// support.
+//
+// Author:
+//
+// David N. Cutler (davec) 5-Mar-1994
+//
+// Environment:
+//
+// Kernel mode only.
+//
+// Revision History:
+//
+//--
+
+#include "halmips.h"
+
+ SBTTL("Processor Idle")
+//++
+//
+// VOID
+// HalProcessorIdle(
+// VOID
+// )
+//
+// Routine Description:
+//
+// This function is called when the current processor is idle with
+// interrupts disabled. There is no thread active and there are no
+// DPCs to process. Therefore, power can be switched to a standby
+// mode until the the next interrupt occurs on the current processor.
+//
+// N.B. This routine is entered with IE in PSR clear. This routine
+// must do any power management enabling necessary, set the IE
+// bit in PSR, then either return or wait for an interrupt.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalProcessorIdle)
+
+//
+// Perform power management enabling.
+//
+
+ .set noreorder
+ .set noat
+ mfc0 v0,psr // get current PSR
+ nop // fill
+ or v0,v0,1 << PSR_IE // set interrupt enable.
+ mtc0 v0,psr // enable interrupts
+ .set at
+ .set reorder
+
+//
+// Wait for an interrupt if supported.
+//
+
+ j ra // return
+
+ .end HalProcessorIdle
diff --git a/private/ntos/nthals/haldti/mips/xxinithl.c b/private/ntos/nthals/haldti/mips/xxinithl.c
new file mode 100644
index 000000000..d55d826f1
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/xxinithl.c
@@ -0,0 +1,269 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ xxinithl.c
+
+Abstract:
+
+
+ This module implements the initialization of the system dependent
+ functions that define the Hardware Architecture Layer (HAL) for a
+ MIPS R3000 or R4000 system.
+
+Author:
+
+ David N. Cutler (davec) 25-Apr-1991
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+
+ULONG HalpBusType = MACHINE_TYPE_EISA;
+ULONG HalpMapBufferSize;
+PHYSICAL_ADDRESS HalpMapBufferPhysicalAddress;
+BOOLEAN LessThan16Mb;
+PVOID SecondaryCachePurgeBaseAddress = (PVOID)(0x80f00000);
+ULONG IoSpaceAlreadyMapped = FALSE;
+
+
+BOOLEAN
+HalInitSystem (
+ IN ULONG Phase,
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ )
+
+/*++
+
+Routine Description:
+
+ This function initializes the Hardware Architecture Layer (HAL) for a
+ MIPS R3000 or R4000 system.
+
+Arguments:
+
+ Phase - Supplies the initialization phase (zero or one).
+
+ LoaderBlock - Supplies a pointer to a loader parameter block.
+
+Return Value:
+
+ A value of TRUE is returned is the initialization was successfully
+ complete. Otherwise a value of FALSE is returend.
+
+--*/
+
+{
+ PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
+ PLIST_ENTRY NextMd;
+ PKPRCB Prcb;
+ ULONG BuildType = 0;
+
+ Prcb = KeGetCurrentPrcb();
+ if (Phase == 0) {
+
+ //
+ // Phase 0 initialization.
+ //
+ // Verify that the processor block major version number conform
+ // to the system that is being loaded.
+ //
+
+ if (Prcb->MajorVersion != PRCB_MAJOR_VERSION) {
+ KeBugCheck(MISMATCHED_HAL);
+ }
+
+ //
+ // Set the number of process id's and TB entries.
+ //
+
+ **((PULONG *)(&KeNumberProcessIds)) = 256;
+ **((PULONG *)(&KeNumberTbEntries)) = 48;
+
+ //
+ // Set the time increment value.
+ //
+
+ HalpCurrentTimeIncrement = MAXIMUM_INCREMENT;
+ HalpNextTimeIncrement = MAXIMUM_INCREMENT;
+ HalpNextIntervalCount = 0;
+ KeSetTimeIncrement(MAXIMUM_INCREMENT, MINIMUM_INCREMENT);
+ LessThan16Mb = TRUE;
+
+ SecondaryCachePurgeBaseAddress = NULL;
+
+ NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
+
+ while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {
+ Descriptor = CONTAINING_RECORD( NextMd,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry );
+
+// To purge the secondary cache on an ArcStation I, a valid Firmware Permanent
+// region must be found that starts on a 512 KB boundry and is at least
+// 512 KB long. The secondary cache is purged by reading from the appropriate
+// range of this 512 KB region for the page being purged.
+
+ if (Descriptor->MemoryType == LoaderFirmwarePermanent &&
+ (Descriptor->BasePage % 128)==0 &&
+ Descriptor->PageCount>=128) {
+
+ SecondaryCachePurgeBaseAddress = (PVOID)(KSEG0_BASE | (Descriptor->BasePage*4096));
+
+ Descriptor->BasePage+=128;
+ Descriptor->PageCount-=128;
+
+ }
+
+ if (Descriptor->BasePage + Descriptor->PageCount > 0x1000) {
+ LessThan16Mb = FALSE;
+ }
+
+ NextMd = Descriptor->ListEntry.Flink;
+ }
+
+ if (SecondaryCachePurgeBaseAddress==NULL) {
+ HalDisplayString("ERROR : A valid Firmware Permanent area does not exist\n");
+ KeBugCheck(PHASE0_INITIALIZATION_FAILED);
+ }
+
+ //
+ // Determine the size need for map buffers. If this system has
+ // memory with a physical address of greater than
+ // MAXIMUM_PHYSICAL_ADDRESS, then allocate a large chunk; otherwise,
+ // allocate a small chunk.
+ //
+
+ if (LessThan16Mb) {
+
+ //
+ // Allocate a small set of map buffers. They are only need for
+ // slave DMA devices.
+ //
+
+ HalpMapBufferSize = INITIAL_MAP_BUFFER_SMALL_SIZE;
+
+ } else {
+
+ //
+ // Allocate a larger set of map buffers. These are used for
+ // slave DMA controllers and Isa cards.
+ //
+
+ HalpMapBufferSize = INITIAL_MAP_BUFFER_LARGE_SIZE;
+
+ }
+
+ HalpMapBufferPhysicalAddress.LowPart =
+ HalpAllocPhysicalMemory (LoaderBlock, MAXIMUM_ISA_PHYSICAL_ADDRESS,
+ HalpMapBufferSize >> PAGE_SHIFT, FALSE);
+ HalpMapBufferPhysicalAddress.HighPart = 0;
+
+ if (!HalpMapBufferPhysicalAddress.LowPart) {
+
+ //
+ // There was not a satisfactory block. Clear the allocation.
+ //
+
+ HalpMapBufferSize = 0;
+ }
+
+ //
+ // Initialize interrupts.
+ //
+
+
+ HalpInitializeInterrupts();
+ return TRUE;
+
+ } else {
+
+ //
+ // Phase 1 initialization.
+ //
+
+ if (IoSpaceAlreadyMapped == FALSE) {
+ HalpMapIoSpace();
+ HalpInitializeX86DisplayAdapter();
+ IoSpaceAlreadyMapped = TRUE;
+ }
+
+ HalpCreateDmaStructures();
+ HalpCalibrateStall();
+ 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 ()
+{
+
+}
diff --git a/private/ntos/nthals/haldti/mips/xxinitnt.c b/private/ntos/nthals/haldti/mips/xxinitnt.c
new file mode 100644
index 000000000..9053b05e9
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/xxinitnt.c
@@ -0,0 +1,158 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ xxinitnt.c
+
+Abstract:
+
+
+ This module implements the interrupt initialization for a MIPS R3000
+ or R4000 system.
+
+Author:
+
+ David N. Cutler (davec) 26-Apr-1991
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+
+//
+// Define the IRQL mask and level mapping table.
+//
+// These tables are transfered to the PCR and determine the priority of
+// interrupts.
+//
+// N.B. The two software interrupt levels MUST be the lowest levels.
+//
+
+UCHAR HalpIrqlMask[] = {4, 5, 6, 6, 7, 7, 7, 7, // 0000 - 0111 high 4-bits
+ 8, 8, 8, 8, 8, 8, 8, 8, // 1000 - 1111 high 4-bits
+ 0, 1, 2, 2, 3, 3, 3, 3, // 0000 - 0111 low 4-bits
+ 4, 4, 4, 4, 4, 4, 4, 4}; // 1000 - 1111 low 4-bits
+
+UCHAR HalpIrqlTable[] = {0xff, // IRQL 0
+ 0xfe, // IRQL 1
+ 0xfc, // IRQL 2
+ 0xf8, // IRQL 3
+ 0xf0, // IRQL 4
+ 0xe0, // IRQL 5
+ 0xc0, // IRQL 6
+ 0x80, // IRQL 7
+ 0x00}; // IRQL 8
+
+#if defined(R4000)
+
+VOID
+HalpCountInterrupt (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function serves as the R4000 count/compare interrupt service
+ routine early in the system initialization. Its only function is
+ to field and acknowledge count/compare interrupts during the system
+ boot process.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Acknowledge the R4000 count/compare interrupt.
+ //
+
+ HalpWriteCompareRegisterAndClear(DEFAULT_PROFILE_COUNT);
+ return;
+}
+
+#endif
+
+BOOLEAN
+HalpInitializeInterrupts (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function initializes interrupts for a MIPS R3000 or R4000 system.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A value of TRUE is returned if the initialization is successfully
+ completed. Otherwise a value of FALSE is returned.
+
+--*/
+
+{
+ ULONG Index;
+ PKPRCB Prcb;
+
+ //
+ // Get the address of the processor control block for the current
+ // processor.
+ //
+
+ Prcb = PCR->Prcb;
+
+ //
+ // Initialize the IRQL translation tables in the PCR. These tables are
+ // used by the interrupt dispatcher to determine the new IRQL and the
+ // mask value that is to be loaded into the PSR. They are also used by
+ // the routines that raise and lower IRQL to load a new mask value into
+ // the PSR.
+ //
+
+ for (Index = 0; Index < sizeof(HalpIrqlMask); Index += 1) {
+ PCR->IrqlMask[Index] = HalpIrqlMask[Index];
+ }
+
+ for (Index = 0; Index < sizeof(HalpIrqlTable); Index += 1) {
+ PCR->IrqlTable[Index] = HalpIrqlTable[Index];
+ }
+
+ //
+ // Connect the clock interrupt to the stall interrupt routine.
+ //
+
+ PCR->InterruptRoutine[CLOCK2_LEVEL] = HalpStallInterrupt;
+
+ //
+ // Connect the R4000 count/compare interrupt to the early interrupt
+ // routine.
+ //
+
+#if defined(R4000)
+
+ PCR->InterruptRoutine[PROFILE_LEVEL] = HalpCountInterrupt;
+
+#endif
+
+ return TRUE;
+}
diff --git a/private/ntos/nthals/haldti/mips/xxmemory.c b/private/ntos/nthals/haldti/mips/xxmemory.c
new file mode 100644
index 000000000..30ed99db8
--- /dev/null
+++ b/private/ntos/nthals/haldti/mips/xxmemory.c
@@ -0,0 +1,170 @@
+/*++
+
+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)) {
+ if ((Descriptor->MemoryType == MemoryFirmwarePermanent) &&
+ (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;
+}