From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/ntos/nthals/haldti/drivesup.c | 7 + private/ntos/nthals/haldti/hal.rc | 11 + private/ntos/nthals/haldti/hal.src | 7 + private/ntos/nthals/haldti/makefile | 6 + private/ntos/nthals/haldti/makefile.inc | 6 + private/ntos/nthals/haldti/mips/allstart.c | 56 + private/ntos/nthals/haldti/mips/dtidef.h | 147 ++ private/ntos/nthals/haldti/mips/halp.h | 179 +++ private/ntos/nthals/haldti/mips/j4cache.s | 1026 ++++++++++++ private/ntos/nthals/haldti/mips/j4flshbf.s | 61 + private/ntos/nthals/haldti/mips/j4flshio.c | 264 ++++ private/ntos/nthals/haldti/mips/j4prof.c | 291 ++++ private/ntos/nthals/haldti/mips/jxbeep.c | 125 ++ private/ntos/nthals/haldti/mips/jxdisp.c | 246 +++ private/ntos/nthals/haldti/mips/jxebsup.c | 2376 ++++++++++++++++++++++++++++ private/ntos/nthals/haldti/mips/jxenvirv.c | 98 ++ private/ntos/nthals/haldti/mips/jxhalp.h | 105 ++ private/ntos/nthals/haldti/mips/jxhwsup.c | 2024 ++++++++++++++++++++++++ private/ntos/nthals/haldti/mips/jxmapio.c | 78 + private/ntos/nthals/haldti/mips/jxport.c | 773 +++++++++ private/ntos/nthals/haldti/mips/jxreturn.c | 89 ++ private/ntos/nthals/haldti/mips/jxsysint.c | 252 +++ private/ntos/nthals/haldti/mips/jxtime.c | 278 ++++ private/ntos/nthals/haldti/mips/jxusage.c | 48 + private/ntos/nthals/haldti/mips/x4clock.s | 210 +++ private/ntos/nthals/haldti/mips/x86bios.c | 262 +++ private/ntos/nthals/haldti/mips/x86bios.h | 11 + private/ntos/nthals/haldti/mips/x86lator.c | 11 + private/ntos/nthals/haldti/mips/xxcalstl.c | 291 ++++ private/ntos/nthals/haldti/mips/xxclock.c | 171 ++ private/ntos/nthals/haldti/mips/xxidle.s | 79 + private/ntos/nthals/haldti/mips/xxinithl.c | 269 ++++ private/ntos/nthals/haldti/mips/xxinitnt.c | 158 ++ private/ntos/nthals/haldti/mips/xxmemory.c | 170 ++ private/ntos/nthals/haldti/sources | 84 + 35 files changed, 10269 insertions(+) create mode 100644 private/ntos/nthals/haldti/drivesup.c create mode 100644 private/ntos/nthals/haldti/hal.rc create mode 100644 private/ntos/nthals/haldti/hal.src create mode 100644 private/ntos/nthals/haldti/makefile create mode 100644 private/ntos/nthals/haldti/makefile.inc create mode 100644 private/ntos/nthals/haldti/mips/allstart.c create mode 100644 private/ntos/nthals/haldti/mips/dtidef.h create mode 100644 private/ntos/nthals/haldti/mips/halp.h create mode 100644 private/ntos/nthals/haldti/mips/j4cache.s create mode 100644 private/ntos/nthals/haldti/mips/j4flshbf.s create mode 100644 private/ntos/nthals/haldti/mips/j4flshio.c create mode 100644 private/ntos/nthals/haldti/mips/j4prof.c create mode 100644 private/ntos/nthals/haldti/mips/jxbeep.c create mode 100644 private/ntos/nthals/haldti/mips/jxdisp.c create mode 100644 private/ntos/nthals/haldti/mips/jxebsup.c create mode 100644 private/ntos/nthals/haldti/mips/jxenvirv.c create mode 100644 private/ntos/nthals/haldti/mips/jxhalp.h create mode 100644 private/ntos/nthals/haldti/mips/jxhwsup.c create mode 100644 private/ntos/nthals/haldti/mips/jxmapio.c create mode 100644 private/ntos/nthals/haldti/mips/jxport.c create mode 100644 private/ntos/nthals/haldti/mips/jxreturn.c create mode 100644 private/ntos/nthals/haldti/mips/jxsysint.c create mode 100644 private/ntos/nthals/haldti/mips/jxtime.c create mode 100644 private/ntos/nthals/haldti/mips/jxusage.c create mode 100644 private/ntos/nthals/haldti/mips/x4clock.s create mode 100644 private/ntos/nthals/haldti/mips/x86bios.c create mode 100644 private/ntos/nthals/haldti/mips/x86bios.h create mode 100644 private/ntos/nthals/haldti/mips/x86lator.c create mode 100644 private/ntos/nthals/haldti/mips/xxcalstl.c create mode 100644 private/ntos/nthals/haldti/mips/xxclock.c create mode 100644 private/ntos/nthals/haldti/mips/xxidle.s create mode 100644 private/ntos/nthals/haldti/mips/xxinithl.c create mode 100644 private/ntos/nthals/haldti/mips/xxinitnt.c create mode 100644 private/ntos/nthals/haldti/mips/xxmemory.c create mode 100644 private/ntos/nthals/haldti/sources (limited to 'private/ntos/nthals/haldti') diff --git a/private/ntos/nthals/haldti/drivesup.c b/private/ntos/nthals/haldti/drivesup.c new file mode 100644 index 000000000..38259e5f4 --- /dev/null +++ b/private/ntos/nthals/haldti/drivesup.c @@ -0,0 +1,7 @@ +// +// This file simply includes the common sources from the current HAL +// directory. When the structure is finally changed, the real file should +// be in this directory. +// + +#include "..\drivesup.c" diff --git a/private/ntos/nthals/haldti/hal.rc b/private/ntos/nthals/haldti/hal.rc new file mode 100644 index 000000000..3cba4ad89 --- /dev/null +++ b/private/ntos/nthals/haldti/hal.rc @@ -0,0 +1,11 @@ +#include + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "Hardware Abstraction Layer DLL" +#define VER_INTERNALNAME_STR "hal.dll" + +#include "common.ver" + diff --git a/private/ntos/nthals/haldti/hal.src b/private/ntos/nthals/haldti/hal.src new file mode 100644 index 000000000..da778bb9d --- /dev/null +++ b/private/ntos/nthals/haldti/hal.src @@ -0,0 +1,7 @@ +// +// This file simply includes the common sources from the current HAL +// directory. When the structure is finally changed, the real file should +// be in this directory. +// + +#include "..\hal.src" diff --git a/private/ntos/nthals/haldti/makefile b/private/ntos/nthals/haldti/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/ntos/nthals/haldti/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/ntos/nthals/haldti/makefile.inc b/private/ntos/nthals/haldti/makefile.inc new file mode 100644 index 000000000..2558bb59f --- /dev/null +++ b/private/ntos/nthals/haldti/makefile.inc @@ -0,0 +1,6 @@ +obj\mips\hal.def: hal.src + rcpp -P -f hal.src -DMIPS=1 $(C_DEFINES) -g obj\mips\hal.def + +$(TARGETPATH)\mips\hal.lib: $(TARGETPATH)\mips\haldti.lib + copy $** $@ + 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<= HalpMapBufferPhysicalAddress.LowPart && + ((*pageFrame<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<= HalpMapBufferPhysicalAddress.LowPart && + ((*pageFrame<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;iNeedsMapRegisters; + 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; +} diff --git a/private/ntos/nthals/haldti/sources b/private/ntos/nthals/haldti/sources new file mode 100644 index 000000000..8573a033a --- /dev/null +++ b/private/ntos/nthals/haldti/sources @@ -0,0 +1,84 @@ +!IF 0 + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + David N. Cutler (davec) 8-Apr-1993 + +NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl + +!ENDIF + +MAJORCOMP=ntos +MINORCOMP=hal + +TARGETNAME=haldti +TARGETPATH=\nt\public\sdk\lib +TARGETLIBS=\nt\private\ntos\nthals\x86new\obj\mips\x86new.lib \ + \nt\public\sdk\lib\*\libcntpr.lib + +!IF $(MIPS) + +TARGETTYPE=HAL + +!ELSE + +TARGETTYPE=DRIVER + +!ENDIF + +INCLUDES=..\x86new;..\..\inc + +MIPS_ENABLE_MIPS3=1 + +MSC_WARNING_LEVEL=/W3 /WX + +SOURCES= + +MIPS_SOURCES=hal.rc \ + drivesup.c \ + mips\allstart.c \ + mips\jxbeep.c \ + mips\jxenvirv.c \ + mips\j4flshbf.s \ + mips\j4flshio.c \ + mips\jxdisp.c \ + mips\jxebsup.c \ + mips\jxhwsup.c \ + mips\jxmapio.c \ + mips\jxport.c \ + mips\j4cache.s \ + mips\j4prof.c \ + mips\jxreturn.c \ + mips\jxsysint.c \ + mips\jxtime.c \ + mips\jxusage.c \ + mips\x86bios.c \ + mips\x4clock.s \ + mips\xxcalstl.c \ + mips\xxclock.c \ + mips\xxidle.s \ + mips\xxinitnt.c \ + mips\xxinithl.c \ + mips\xxmemory.c + +DLLDEF=obj\*\hal.def + +!IF $(MIPS) + +NTTARGETFILES=$(TARGETPATH)\mips\hal.lib + +!ENDIF -- cgit v1.2.3