diff options
Diffstat (limited to 'private/ntos/nthals/haleagle')
66 files changed, 26187 insertions, 0 deletions
diff --git a/private/ntos/nthals/haleagle/hal.rc b/private/ntos/nthals/haleagle/hal.rc new file mode 100644 index 000000000..3cba4ad89 --- /dev/null +++ b/private/ntos/nthals/haleagle/hal.rc @@ -0,0 +1,11 @@ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "Hardware Abstraction Layer DLL" +#define VER_INTERNALNAME_STR "hal.dll" + +#include "common.ver" + diff --git a/private/ntos/nthals/haleagle/makefile b/private/ntos/nthals/haleagle/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/ntos/nthals/haleagle/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/haleagle/ppc/ctrlops.c b/private/ntos/nthals/haleagle/ppc/ctrlops.c new file mode 100644 index 000000000..f921d2ed6 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/ctrlops.c @@ -0,0 +1,471 @@ +/*++ + +Copyright (c) 1994 Microsoft Corporation + +Module Name: + + ctrlops.c + +Abstract: + + This module implements the code to emulate call, retunr, and various + control operations. + +Author: + + David N. Cutler (davec) 10-Nov-1994 + + +Environment: + + Kernel mode only. + +Revision History: + + Scott Geranen 5-Mar-1996 Added hooks for System BIOS emulation + +--*/ + +#include "nthal.h" +#include "emulate.h" +#include "sysbios.h" + +VOID +XmCallOp ( + PRXM_CONTEXT P + ) + +/*++ + +Routine Description: + + This function emulates a call opcode. + +Arguments: + + P - Supplies a pointer to an emulator context structure. + +Return Value: + + None. + +--*/ + +{ + + ULONG Target; + ULONG Source; + + // + // Save the target address, push the current segment, if required, and + // push the current IP, set the destination segment, if required, and + // set the new IP. + // + + Target = P->DstValue.Long; + if (P->OpsizePrefixActive != FALSE) { + P->DataType = LONG_DATA; + + } else { + P->DataType = WORD_DATA; + } + + if ((P->CurrentOpcode == 0x9a) || (P->FunctionIndex != X86_CALL_OP)) { + XmPushStack(P, P->SegmentRegister[CS]); + XmPushStack(P, P->Eip); + P->SegmentRegister[CS] = P->DstSegment; + + } else { + XmPushStack(P, P->Eip); + } + + P->Eip = Target; + XmTraceJumps(P); + return; +} + +VOID +XmEnterOp ( + PRXM_CONTEXT P + ) + +/*++ + +Routine Description: + + This function emulates an enter opcode. + +Arguments: + + P - Supplies a pointer to an emulator context structure. + +Return Value: + + None. + +--*/ + +{ + + ULONG Allocate; + ULONG Frame; + ULONG Number; + + // + // set the number of bytes to allocate on the stack and the number + // of nesting levels. + // + + Allocate = P->SrcValue.Long; + Number = P->DstValue.Long; + + // + // Set the data type and save the frame pointer on the stack. + // + + if (P->OpsizePrefixActive != FALSE) { + P->DataType = LONG_DATA; + XmPushStack(P, P->Gpr[EBP].Exx); + Frame = P->Gpr[ESP].Exx; + + } else { + P->DataType = WORD_DATA; + XmPushStack(P, P->Gpr[BP].Xx); + Frame = P->Gpr[SP].Xx; + } + + // + // Save the current stack pointer and push parameters on the stack. + // + + if (Number != 0) { + + // + // If the level number is not one, then raise an exception. + // + // N.B. Level numbers greater than one are not supported. + // + + if (Number != 1) { + longjmp(&P->JumpBuffer[0], XM_ILLEGAL_LEVEL_NUMBER); + } + + XmPushStack(P, Frame); + } + + // + // Allocate local storage on stack. + // + + if (P->OpsizePrefixActive != FALSE) { + P->Gpr[EBP].Exx = Frame; + P->Gpr[ESP].Exx = P->Gpr[ESP].Exx - Allocate; + + } else { + P->Gpr[BP].Xx = (USHORT)Frame; + P->Gpr[SP].Xx = (USHORT)(P->Gpr[SP].Xx - Allocate); + } + + return; +} + +VOID +XmHltOp ( + PRXM_CONTEXT P + ) + +/*++ + +Routine Description: + + This function emulates a hlt opcode. + +Arguments: + + P - Supplies a pointer to an emulator context structure. + +Return Value: + + None. + +--*/ + +{ + + // + // Halt instructions are not supported by the emulator. + // + + longjmp(&P->JumpBuffer[0], XM_HALT_INSTRUCTION); + return; +} + +VOID +XmIntOp ( + PRXM_CONTEXT P + ) + +/*++ + +Routine Description: + + This function emulates an int opcode. + +Arguments: + + P - Supplies a pointer to an emulator context structure. + +Return Value: + + None. + +--*/ + +{ + + ULONG Number; + PULONG Vector; + + // + // If the int instruction is an int 3, then set the interrupt vector + // to 3. Otherwise, if the int instruction is an into, then set the + // vector to 4 if OF is set. use the source interrupt vector. + // + + if (P->OpsizePrefixActive != FALSE) { + P->DataType = LONG_DATA; + + } else { + P->DataType = WORD_DATA; + } + + if (P->CurrentOpcode == 0xcc) { + Number = 3; + + } else if (P->CurrentOpcode == 0xce) { + if (P->Eflags.OF == 0) { + return; + } + + Number = 4; + + } else { + Number = P->SrcValue.Byte; + } + + // + // If the vector number is 0x42, then nop the interrupt. This is the + // standard EGA video driver entry point in a PC's motherboard BIOS + // for which there is no code. + // + +#if !defined(_PURE_EMULATION_) + + if (Number == 0x42) { + return; + } + +#endif + + // + // Try to emulate a system BIOS call first. + // + if (!HalpEmulateSystemBios(P, Number)) { + + // + // Either it isn't a BIOS call or it isn't supported. + // Emulate the x86 stream instead. Note that this + // doesn't support chained handlers. + + // + // Push the current flags, code segment, and EIP on the stack. + // + + XmPushStack(P, P->AllFlags); + XmPushStack(P, P->SegmentRegister[CS]); + XmPushStack(P, P->Eip); + + // + // Set the new coded segment and IP from the specified interrupt + // vector. + // + + Vector = (PULONG)(P->TranslateAddress)(0, 0); + P->SegmentRegister[CS] = (USHORT)(Vector[Number] >> 16); + P->Eip = (USHORT)(Vector[Number] & 0xffff); + XmTraceJumps(P); + } + + return; +} + +VOID +XmIretOp ( + PRXM_CONTEXT P + ) + +/*++ + +Routine Description: + + This function emulates an iret opcode. + +Arguments: + + P - Supplies a pointer to an emulator context structure. + +Return Value: + + None. + +--*/ + +{ + + // + // Set the data type and restore the return address, code segment, + // and flags. + // + + if (P->OpsizePrefixActive != FALSE) { + P->DataType = LONG_DATA; + + } else { + P->DataType = WORD_DATA; + } + + P->Eip = XmPopStack(P); + P->SegmentRegister[CS] = (USHORT)XmPopStack(P); + P->AllFlags = XmPopStack(P); + XmTraceJumps(P); + + // + // Check for emulator exit conditions. + // + + if ((P->Eip == 0xffff) && (P->SegmentRegister[CS] == 0xffff)) { + longjmp(&P->JumpBuffer[0], XM_SUCCESS); + } + + return; +} + +VOID +XmLeaveOp ( + PRXM_CONTEXT P + ) + +/*++ + +Routine Description: + + This function emulates a leave opcode. + +Arguments: + + P - Supplies a pointer to an emulator context structure. + +Return Value: + + None. + +--*/ + +{ + + // + // Set the data type, restore the stack pointer, and restore the frame + // pointer. + // + + if (P->OpsizePrefixActive != FALSE) { + P->DataType = LONG_DATA; + P->Gpr[ESP].Exx = P->Gpr[EBP].Exx; + P->Gpr[EBP].Exx = XmPopStack(P); + + } else { + P->DataType = WORD_DATA; + P->Gpr[SP].Xx = P->Gpr[BP].Xx; + P->Gpr[BP].Xx = (USHORT)XmPopStack(P); + } + + return; +} + +VOID +XmRetOp ( + PRXM_CONTEXT P + ) + +/*++ + +Routine Description: + + This function emulates a ret opcode. + +Arguments: + + P - Supplies a pointer to an emulator context structure. + +Return Value: + + None. + +--*/ + +{ + + ULONG Adjust; + + // + // Compute the number of bytes that are to be removed from the stack + // after having removed the return address and optionally the new CS + // segment value. + // + + if ((P->CurrentOpcode & 0x1) == 0) { + Adjust = XmGetWordImmediate(P); + + } else { + Adjust = 0; + } + + // + // Remove the return address from the stack and set the new IP. + // + + if (P->OpsizePrefixActive != FALSE) { + P->DataType = LONG_DATA; + + } else { + P->DataType = WORD_DATA; + } + + P->Eip = XmPopStack(P); + + // + // If the current opcode is a far return, then remove the new CS segment + // value from the stack. + // + + if ((P->CurrentOpcode & 0x8) != 0) { + P->SegmentRegister[CS] = (USHORT)XmPopStack(P); + } + + // + // Remove the specified number of bytes from the stack. + // + + P->Gpr[ESP].Exx += Adjust; + XmTraceJumps(P); + + // + // Check for emulator exit conditions. + // + + if ((P->Eip == 0xffff) && (P->SegmentRegister[CS] == 0xffff)) { + longjmp(&P->JumpBuffer[0], XM_SUCCESS); + } + + return; +} diff --git a/private/ntos/nthals/haleagle/ppc/fwnvr.c b/private/ntos/nthals/haleagle/ppc/fwnvr.c new file mode 100644 index 000000000..859d0aef9 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/fwnvr.c @@ -0,0 +1,1745 @@ +/* +*********************************************************************** +** NVRAM +*********************************************************************** +*/ +#define _NOT_HALNVR_ + +#ifdef _HALNVR_ +#include "halp.h" +#else +#include "fwp.h" +#endif /* _HALNVR_ */ + +#include "prepnvr.h" +#include "fwstatus.h" +#include "fwnvr.h" + +/* +*********************************************************************** +** internal type definitions +*********************************************************************** +*/ +typedef struct _nvrregs { + UCHAR reserved_0[0x74]; + UCHAR addl; /* low half of address register */ + UCHAR addh; /* high half of address register */ + UCHAR polodata; /* NVRAM Data Port on Polo */ + UCHAR sfdata; /* NVRAM Data Port on Sandalfoot */ + UCHAR reserved_1[0x800-0x78]; + UCHAR bb_data; /* NVRAM Data Port on BigBend (0x800) */ + UCHAR reserved_2[0x400-1]; + UCHAR bb_addl; /* NVRAM Lo Index Port on BigBend (0xC00) */ + UCHAR bb_addh; /* NVRAM Hi Index Port on BigBend (0xC01) */ + + } NVRREGS, *PNVRREGS; + +typedef struct _nvr_object { + struct _nvr_object *self; + NVR_SYSTEM_TYPE systype; + HEADER* bhead; + HEADER* lhead; + UCHAR bend[NVSIZE*2]; + UCHAR lend[NVSIZE*2]; + } NVR_OBJECT, *PNVR_OBJECT; + +typedef NVRAM_MAP *PNVRAM_MAP; + +/* +*********************************************************************** +** private macros, defines, and externs +*********************************************************************** +*/ +extern PVOID HalpIoControlBase; +#define NVRAM_VIRTUAL_BASE ((PUCHAR)HalpIoControlBase) + +#define _ppc_shortswap(_x) (((_x<<8)&0xff00)|((_x>>8)&0x00ff)) + +#define _ppc_longswap(_x)\ +(((_x<<24)&0xff000000)|((_x<<8)&0x00ff0000)|\ +((_x>>8)&0x0000ff00)|((_x>>24)&0x000000ff)) + +#define _toupr_(_c) (((_c >= 'a') && (_c <= 'z')) ? (_c - 'a' + 'A') : _c) + +#define MAXNVRFETCH NVSIZE*2 + +/* +*********************************************************************** +** prototypes of private methods +** (prototypes of public methods are defined in fwnvr.h) +*********************************************************************** +*/ + +VOID nvr_clear_nvram(PNVR_OBJECT); +UCHAR nvr_read(NVR_SYSTEM_TYPE, ULONG); +VOID nvr_write(NVR_SYSTEM_TYPE, ULONG,UCHAR); +PNVR_OBJECT nvr_create_object(NVR_SYSTEM_TYPE); +PNVR_OBJECT nvr_alloc(ULONG); +VOID nvr_free(PVOID); +VOID nvr_default_nvram(PNVR_OBJECT); +VOID nvr_read_nvram(PNVR_OBJECT); +VOID nvr_write_Header(PNVR_OBJECT); +VOID nvr_swap_Header(HEADER*, HEADER*); +VOID nvr_headb2l(PNVR_OBJECT); +VOID nvr_headl2b(PNVR_OBJECT); +ULONG nvr_computecrc(ULONG, UCHAR); +USHORT nvr_calc1crc(PNVR_OBJECT); +USHORT nvr_calc2crc(PNVR_OBJECT); +VOID nvr_read_GEArea(PNVR_OBJECT); +VOID nvr_read_OSArea(PNVR_OBJECT); +VOID nvr_read_CFArea(PNVR_OBJECT); +VOID nvr_write_GEArea(PNVR_OBJECT); +VOID nvr_write_OSArea(PNVR_OBJECT); +VOID nvr_write_CFArea(PNVR_OBJECT); + +/* +*********************************************************************** +** prototypes of private debug methods are defined below +*********************************************************************** +*/ +//#undef KDB +#ifdef KDB +VOID nvr_display_object(PNVR_OBJECT); +VOID nvr_display_lemap(PNVR_OBJECT); +VOID nvr_display_bemap(PNVR_OBJECT); +VOID nvr_test_setvar(VOID); +#endif /* KDB */ + +/* +*********************************************************************** +** private data items - not visible to public clients +*********************************************************************** +*/ + +UCHAR _currentstring[MAXIMUM_ENVIRONMENT_VALUE]; +UCHAR _currentfetch[MAXNVRFETCH]; + +#ifndef _HALNVR_ +NVR_OBJECT nvrobj; +#endif /* _HALNVR_ */ + +PNVR_OBJECT pnvrobj = 0; + +/* +*********************************************************************** +** methods +*********************************************************************** +*/ + +/***********************************************************************/ +PNVR_OBJECT nvr_alloc(ULONG size) +{ + PNVR_OBJECT p; + + p = (PNVR_OBJECT)0; + +#ifdef _HALNVR_ + /* use HAL memory allocation here */ + p = ExAllocatePool(NonPagedPool, size); + return(p); +#else + /* use ARC FW memory allocation here */ + p = &nvrobj; + return(p); +#endif /* _HALNVR_ */ +} + +/***********************************************************************/ +VOID nvr_free(PVOID p) +{ + if (p == (PVOID)NULL) + return; + +#ifdef _HALNVR_ + /* use HAL memory deallocation here */ + ExFreePool(p); +#endif /* _HALNVR_ */ + + return; +} + +/***********************************************************************/ +UCHAR nvr_read(NVR_SYSTEM_TYPE st, ULONG addr) +{ + UCHAR uc; + UCHAR hi_index, lo_index; + PNVRREGS nvp = (PNVRREGS)NVRAM_VIRTUAL_BASE; + lo_index = (UCHAR)(addr & 0xff); + hi_index = (UCHAR)((addr >> 8) & 0x1f); + switch (st) { + case nvr_systype_bigbend: + WRITE_REGISTER_UCHAR(&nvp->bb_addl, lo_index); + WRITE_REGISTER_UCHAR(&nvp->bb_addh, hi_index); + break; + default: + WRITE_REGISTER_UCHAR(&nvp->addl, lo_index); + WRITE_REGISTER_UCHAR(&nvp->addh, hi_index); + break; + } +#ifndef _HALNVR_ + Eieio(); +#endif /* _HALNVR_ */ + + switch (st) { + case nvr_systype_powerstack: + case nvr_systype_sandalfoot: + uc = READ_REGISTER_UCHAR(&nvp->sfdata); + break; + case nvr_systype_bigbend: + uc = READ_REGISTER_UCHAR(&nvp->bb_data); + break; + case nvr_systype_polo: + case nvr_systype_woodfield: + uc = READ_REGISTER_UCHAR(&nvp->polodata); + break; + default: + uc = 0; + break; + } + + return(uc); +} + +/***********************************************************************/ +VOID nvr_write(NVR_SYSTEM_TYPE st, ULONG addr, UCHAR data) +{ + UCHAR hi_index, lo_index; + PNVRREGS nvp = (PNVRREGS)NVRAM_VIRTUAL_BASE; + + lo_index = (UCHAR)(addr & 0xff); + hi_index = (UCHAR)((addr >> 8) & 0x1f); + switch (st) { + case nvr_systype_bigbend: + WRITE_REGISTER_UCHAR(&nvp->bb_addl, lo_index); + WRITE_REGISTER_UCHAR(&nvp->bb_addh, hi_index); + break; + default: + WRITE_REGISTER_UCHAR(&nvp->addl, lo_index); + WRITE_REGISTER_UCHAR(&nvp->addh, hi_index); + break; + } +#ifndef _HALNVR_ + Eieio(); +#endif /* _HALNVR_ */ + + switch (st) { + case nvr_systype_powerstack: + case nvr_systype_sandalfoot: + WRITE_REGISTER_UCHAR(&nvp->sfdata, data); + break; + case nvr_systype_bigbend: + WRITE_REGISTER_UCHAR(&nvp->bb_data, data); + break; + case nvr_systype_polo: + case nvr_systype_woodfield: + WRITE_REGISTER_UCHAR(&nvp->polodata, data); + break; + default: + break; + } + +#ifndef _HALNVR_ + Eieio(); +#endif /* _HALNVR_ */ + + return; +} + +/***********************************************************************/ +VOID nvr_swap_Header(HEADER* dest, HEADER* src) +{ + ULONG i; + PUCHAR cp; + + /* validate pointers */ + if ((dest == NULL) || (src == NULL)) + return; + + dest->Size = _ppc_shortswap(src->Size); + dest->Version = src->Version; + dest->Revision = src->Revision; + dest->Crc1 = _ppc_shortswap(src->Crc1); + dest->Crc2 = _ppc_shortswap(src->Crc2); + dest->LastOS = src->LastOS; + dest->Endian = src->Endian; + dest->OSAreaUsage = src->OSAreaUsage; + dest->PMMode = src->PMMode; + + /* convert NVRRESTART_BLOCK structure of Header */ + dest->ResumeBlock.CheckSum = _ppc_longswap(src->ResumeBlock.CheckSum); + dest->ResumeBlock.BootStatus = _ppc_longswap(src->ResumeBlock.BootStatus); + dest->ResumeBlock.ResumeAddr = + (VOID *) _ppc_longswap((ULONG)src->ResumeBlock.ResumeAddr); + dest->ResumeBlock.SaveAreaAddr = + (VOID *) _ppc_longswap((ULONG)src->ResumeBlock.SaveAreaAddr); + dest->ResumeBlock.SaveAreaLength = + _ppc_longswap((ULONG)src->ResumeBlock.SaveAreaLength); + dest->ResumeBlock.HibResumeImageRBA = + _ppc_longswap((ULONG)src->ResumeBlock.HibResumeImageRBA); + dest->ResumeBlock.HibResumeImageRBACount = + _ppc_longswap((ULONG)src->ResumeBlock.HibResumeImageRBACount); + dest->ResumeBlock.Reserved = + _ppc_longswap((ULONG)src->ResumeBlock.Reserved); + + /* convert SECURITY structure */ + dest->Security.BootErrCnt = + _ppc_longswap(src->Security.BootErrCnt); + dest->Security.ConfigErrCnt = + _ppc_longswap(src->Security.ConfigErrCnt); + dest->Security.BootErrorDT[0] = + _ppc_longswap(src->Security.BootErrorDT[0]); + dest->Security.BootErrorDT[1] = + _ppc_longswap(src->Security.BootErrorDT[1]); + dest->Security.ConfigErrorDT[0] = + _ppc_longswap(src->Security.ConfigErrorDT[0]); + dest->Security.ConfigErrorDT[1] = + _ppc_longswap(src->Security.ConfigErrorDT[1]); + dest->Security.BootCorrectDT[0] = + _ppc_longswap(src->Security.BootCorrectDT[0]); + dest->Security.BootCorrectDT[1] = + _ppc_longswap(src->Security.BootCorrectDT[1]); + dest->Security.ConfigCorrectDT[0] = + _ppc_longswap(src->Security.ConfigCorrectDT[0]); + dest->Security.ConfigCorrectDT[1] = + _ppc_longswap(src->Security.ConfigCorrectDT[1]); + dest->Security.BootSetDT[0] = + _ppc_longswap(src->Security.BootSetDT[0]); + dest->Security.BootSetDT[1] = + _ppc_longswap(src->Security.BootSetDT[1]); + dest->Security.ConfigSetDT[0] = + _ppc_longswap(src->Security.ConfigSetDT[0]); + dest->Security.ConfigSetDT[1] = + _ppc_longswap(src->Security.ConfigSetDT[1]); + for (i = 0; i < 16; i++) + dest->Security.Serial[i] = src->Security.Serial[i]; + + /* convert ERROR_LOG 0 and ERROR_LOG 1 structure */ + for (i = 0; i < 40; i++) { + dest->ErrorLog[0].ErrorLogEntry[i] = src->ErrorLog[0].ErrorLogEntry[i]; + dest->ErrorLog[1].ErrorLogEntry[i] = src->ErrorLog[1].ErrorLogEntry[i]; + } + + /* convert remainder of Header */ + dest->GEAddress = (VOID *) _ppc_longswap((ULONG)src->GEAddress); + dest->GELength = _ppc_longswap(src->GELength); + dest->GELastWriteDT[0] = _ppc_longswap(src->GELastWriteDT[0]); + dest->GELastWriteDT[1] = _ppc_longswap(src->GELastWriteDT[1]); + + dest->ConfigAddress = + (VOID *)_ppc_longswap((ULONG)src->ConfigAddress); + dest->ConfigLength = _ppc_longswap(src->ConfigLength); + dest->ConfigLastWriteDT[0] = + _ppc_longswap(src->ConfigLastWriteDT[0]); + dest->ConfigLastWriteDT[1] = + _ppc_longswap(src->ConfigLastWriteDT[1]); + dest->ConfigCount = _ppc_longswap(src->ConfigCount); + + dest->OSAreaAddress = + (VOID *)_ppc_longswap((ULONG)src->OSAreaAddress); + dest->OSAreaLength = _ppc_longswap(src->OSAreaLength); + dest->OSAreaLastWriteDT[0] = + _ppc_longswap(src->OSAreaLastWriteDT[0]); + dest->OSAreaLastWriteDT[1] = + _ppc_longswap(src->OSAreaLastWriteDT[1]); + + return; +} + +/***********************************************************************/ +VOID nvr_headb2l(PNVR_OBJECT p) +{ + ULONG i; + PUCHAR cp; + HEADER *dest; + HEADER *src; + + /* validate pointer */ + if ((p == NULL) || (p != p->self)) + return; + + dest = (HEADER*)p->lend; + src = (HEADER*)p->bend; + + nvr_swap_Header(dest, src); + + return; +} + +/***********************************************************************/ +VOID nvr_headl2b(PNVR_OBJECT p) +{ + ULONG i; + PUCHAR cp; + HEADER *dest; + HEADER *src; + + /* validate pointer */ + if ((p == NULL) || (p != p->self)) + return; + + dest = (HEADER*)p->bend; + src = (HEADER*)p->lend; + + nvr_swap_Header(dest, src); + + return; +} + +/* +*********************************************************************** +** the following attempts to protect operation from faulty +** intitialization of NVRAM by early versions of the machine FW +*********************************************************************** +*/ +#define GEASIZE (NVSIZE-CONFSIZE-OSAREASIZE-sizeof(HEADER)) +VOID nvr_default_nvram(PNVR_OBJECT p) +{ + ULONG i; + PUCHAR cp; + HEADER* bethp; + +#ifdef KDB +DbgPrint("************** nvr_default_nvram: entry\n"); +#endif /* KDB */ + + /* validate pointer */ + if ((p == NULL) || (p != p->self)) + return; + + /* clear the chip memory */ + nvr_clear_nvram(p); + + cp = (PUCHAR)p->bend; + bethp = (HEADER *) cp; + /* clear internal header */ + for (i = 0; i < sizeof(HEADER); i++) + *cp++ = 0; + + /* clear internal data areas */ + for (i = 0; i < (NVSIZE*2); i++) + p->bend[i] = p->lend[i] = 0; + + /* initialize size according to what we know about type */ + if (p->systype == nvr_systype_polo) + bethp->Size = _ppc_shortswap((USHORT)8); + else if (p->systype == nvr_systype_woodfield) + bethp->Size = _ppc_shortswap((USHORT)8); + else + bethp->Size = _ppc_shortswap((USHORT)4); + bethp->Endian = 'B'; + + /* init the header to default values */ + if (_ppc_shortswap((USHORT)bethp->Size) == 8) { + /* size of NVRAM is 8k */ + if (_ppc_longswap((ULONG)bethp->GEAddress) == 0) { + bethp->GEAddress = (VOID *)_ppc_longswap((ULONG)sizeof(HEADER)); + bethp->GELength = _ppc_longswap((ULONG)GEASIZE+NVSIZE); + } + if (_ppc_longswap((ULONG)bethp->OSAreaAddress) == 0) { + bethp->OSAreaAddress = + (VOID *)_ppc_longswap((ULONG)((NVSIZE*2)-(CONFSIZE+OSAREASIZE))); + bethp->OSAreaLength = + _ppc_longswap((ULONG)OSAREASIZE); + } + if (_ppc_longswap((ULONG)bethp->ConfigAddress) == 0) { + bethp->ConfigAddress = (VOID *)_ppc_longswap((ULONG)(NVSIZE*2)); + bethp->ConfigLength = _ppc_longswap((ULONG)0); + } + } + else { + /* size is assumed to be 4k */ + if (_ppc_longswap((ULONG)bethp->GEAddress) == 0) { + bethp->GEAddress = (VOID *)_ppc_longswap((ULONG)sizeof(HEADER)); + bethp->GELength = _ppc_longswap((ULONG)GEASIZE); + } + if (_ppc_longswap((ULONG)bethp->OSAreaAddress) == 0) { + bethp->OSAreaAddress = + (VOID *)_ppc_longswap((ULONG)(NVSIZE-(CONFSIZE+OSAREASIZE))); + bethp->OSAreaLength = + _ppc_longswap((ULONG)OSAREASIZE); + } + if (_ppc_longswap((ULONG)bethp->ConfigAddress) == 0) { + bethp->ConfigAddress = (VOID *)_ppc_longswap((ULONG)NVSIZE); + bethp->ConfigLength = _ppc_longswap((ULONG)0); + } + } + + /* transfer data to little endian (internal) side */ + nvr_headb2l(p); + + /* write the default header to chip memory */ + nvr_write_Header(p); + +#ifdef KDB +DbgPrint("************** nvr_default_nvram: exit\n"); +#endif /* KDB */ + return; +} + +/***********************************************************************/ +VOID nvr_read_nvram(PNVR_OBJECT p) +{ + ULONG i; + PUCHAR cp; + HEADER* hp; + USHORT us; + USHORT tmp; + +#ifdef KDB + DbgPrint("enter nvr_read_nvram\n"); +#endif /* KDB */ + + /* validate pointer */ + if ((p == NULL) || (p != p->self)) + return; + + /* read data from the NVRAM chip */ + hp = p->bhead; + cp = (PUCHAR)p->bend; + for (i = 0; i < sizeof(HEADER); i++) + *cp++ = nvr_read(p->systype,i); + +#ifdef KDB +DbgPrint("IMMEDIATELY AFTER READ HEADER - NO DATA AREAS READ\n"); +nvr_display_bemap(p); +#endif /* KDB */ + + if ((hp->Endian != 'B') && (hp->Endian != 'L')) { +#ifdef KDB +DbgPrint("BAD ENDIAN\n"); +#endif /* KDB */ + nvr_default_nvram(p); + return; + } + + /* convert big endian to little endian */ + nvr_headb2l(p); + + /* read in data areas */ + nvr_read_GEArea(p); + nvr_read_OSArea(p); + nvr_read_CFArea(p); + +#ifdef KDB +DbgPrint("After Areas\n"); +#endif /* KDB */ + + /* check valid checksum 1 */ + us = _ppc_shortswap(hp->Crc1); + tmp = nvr_calc1crc(p); + if (tmp != us) { +#ifdef KDB + DbgPrint("BADCRC1 nvr_read_nvram: orgcrc1: 0x%08x calccrc1: 0x%08x\n", + (int)us, (int)tmp); +#endif /* KDB */ + nvr_default_nvram(p); + return; + } + +#ifdef KDB +DbgPrint("After CRC1\n"); +#endif /* KDB */ + +#if 0 // Don't let a bad CRC #2 bother us + /* check valid checksum 2 */ + us = _ppc_shortswap(hp->Crc2); + tmp = nvr_calc2crc(p); + if (tmp != us) { +#ifdef KDB + DbgPrint("BADCRC2 nvr_read_nvram: orgcrc2: 0x%08x calccrc2: 0x%08x\n", + (int)us, (int)tmp); +#endif /* KDB */ + nvr_default_nvram(p); + return; + } + +#ifdef KDB +DbgPrint("After CRC2\n"); +#endif /* KDB */ +#endif + +#ifdef KDB +DbgPrint("exit nvr_read_nvram: SUCCESS\n"); +#endif /* KDB */ + + return; +} + +/***********************************************************************/ +VOID nvr_write_Header(PNVR_OBJECT p) +{ + ULONG i; + PUCHAR cp; + USHORT us; + + /* validate pointer */ + if ((p == NULL) || (p != p->self)) + return; + + /* convert little endian to big endian */ + nvr_headl2b(p); + + us = nvr_calc1crc(p); + p->bhead->Crc1 = _ppc_shortswap(us); + us = nvr_calc2crc(p); + p->bhead->Crc2 = _ppc_shortswap(us); + + /* spit out data */ + cp = (PUCHAR)p->bend; + for (i = 0; i < sizeof(HEADER); i++) + nvr_write(p->systype, i, *cp++); + + return; +} + +/***********************************************************************/ +VOID nvr_read_GEArea(PNVR_OBJECT p) +{ + ULONG i; + PUCHAR lp; + PUCHAR bp; + ULONG offset; + + /* validate pointer */ + if ((p == NULL) || (p != p->self)) + return; + + /* suck up global environment data */ + /* and place it in both little and big endian sides */ + offset = (ULONG)p->lhead->GEAddress; + lp = (PUCHAR)((ULONG)p->lhead + offset); + bp = (PUCHAR)((ULONG)p->bhead + offset); + for (i = 0; i < p->lhead->GELength; i++, bp++, lp++) { + *bp = *lp = nvr_read(p->systype, offset + i); + } + + return; +} + +/***********************************************************************/ +VOID nvr_read_OSArea(PNVR_OBJECT p) +{ + ULONG i; + PUCHAR lp; + PUCHAR bp; + ULONG offset; + + /* validate pointer */ + if ((p == NULL) || (p != p->self)) + return; + + /* suck up OS specific data */ + /* and place it in both little and big endian sides */ + offset = (ULONG)p->lhead->OSAreaAddress; + lp = (PUCHAR)((ULONG)p->lhead + offset); + bp = (PUCHAR)((ULONG)p->bhead + offset); + for (i = 0; i < p->lhead->OSAreaLength; i++, bp++, lp++) { + *bp = *lp = nvr_read(p->systype, offset + i); + } + + return; +} + +/***********************************************************************/ +VOID nvr_read_CFArea(PNVR_OBJECT p) +{ + ULONG i; + PUCHAR lp; + PUCHAR bp; + ULONG offset; + + /* validate pointer */ + if ((p == NULL) || (p != p->self)) + return; + + /* suck up configuration data */ + offset = (ULONG) p->lhead->ConfigAddress; + lp = (PUCHAR)((ULONG)p->lhead + offset); + bp = (PUCHAR)((ULONG)p->bhead + offset); + for (i = 0; i < p->lhead->ConfigLength; i++) { + bp[i] = lp[i] = nvr_read(p->systype, (offset + i)); + } + + return; +} + +/***********************************************************************/ +VOID nvr_write_GEArea(PNVR_OBJECT p) +{ + ULONG i; + PUCHAR dest; + PUCHAR src; + ULONG offset; + + /* validate pointer */ + if ((p == NULL) || (p != p->self)) + return; + + /* copy from little endian to big endian staging area */ + offset = (ULONG)p->lhead->GEAddress; + src = (PUCHAR)((ULONG)p->lhead + offset); + dest = (PUCHAR)((ULONG)p->bhead + offset); + for (i = 0; i < p->lhead->GELength; i++, dest++, src++) + *dest = *src; + + /* convert to big endian, compute crc, and write header */ + nvr_write_Header(p); + + /* spit out global environment data */ + src = (PUCHAR)((ULONG)p->bhead + offset); + for (i = 0; i < p->lhead->GELength; i++, src++) { + nvr_write(p->systype, (i + offset), *src); + } + + return; +} + +/***********************************************************************/ +VOID nvr_write_OSArea(PNVR_OBJECT p) +{ + ULONG i; + ULONG offset; + PUCHAR src; + PUCHAR dest; + + /* validate pointer */ + if ((p == NULL) || (p != p->self)) + return; + + /* copy from little endian to big endian staging area */ + offset = (ULONG) p->lhead->OSAreaAddress; + src = (PUCHAR)((ULONG)p->lhead + offset); + dest = (PUCHAR)((ULONG)p->bhead + offset); + for (i = 0; i < p->lhead->OSAreaLength; i++, dest++, src++) + *dest = *src; + + /* spit out OS specific data */ + /* header not needed - no crc for OS Area in Header */ + src = (PUCHAR)((ULONG)p->bhead + offset); + for (i = 0; i < p->lhead->OSAreaLength; i++, src++) { + nvr_write(p->systype, (i + offset), *src); + } + + return; +} + +/***********************************************************************/ +VOID nvr_write_CFArea(PNVR_OBJECT p) +{ + ULONG i; + PUCHAR dest; + PUCHAR src; + ULONG offset; + + /* validate pointer */ + if ((p == NULL) || (p != p->self)) + return; + + /* copy from little endian to big endian staging area */ + offset = (ULONG)p->lhead->ConfigAddress; + dest = (PUCHAR)((ULONG)p->bhead + offset - 1); + src = (PUCHAR)((ULONG)p->lhead + offset - 1); + for (i = 0; i < p->lhead->ConfigLength; i++, dest--, src--) + *dest = *src; + + /* convert to big endian, compute crc, and write header */ + nvr_write_Header(p); + + /* spit out configuration data */ + src = (PUCHAR)((ULONG)p->bhead + offset - 1); + for (i = 1; i <= p->lhead->ConfigLength; i++, src--) { + nvr_write(p->systype, (i + offset), *src); + } + + return; +} + +/***********************************************************************/ +PNVR_OBJECT nvr_create_object(NVR_SYSTEM_TYPE systemtype) +{ + ULONG i; + PUCHAR cp; + UCHAR pid; + + pnvrobj = nvr_alloc(sizeof(NVR_OBJECT)); + + if (pnvrobj) { + /* success */ + /* zero out input area */ + for (i = 0, cp = (PUCHAR)pnvrobj; i < sizeof(NVR_OBJECT); i++, cp++) + *cp = 0; + + /* initialize internal elements */ + pnvrobj->self = pnvrobj; + pnvrobj->bhead = (HEADER *) pnvrobj->bend; + pnvrobj->lhead = (HEADER *) pnvrobj->lend; + + switch (systemtype) { + case nvr_systype_powerstack: + case nvr_systype_sandalfoot: + pnvrobj->systype = nvr_systype_sandalfoot; + break; + case nvr_systype_bigbend: + pnvrobj->systype = nvr_systype_bigbend; + break; + case nvr_systype_polo: + pnvrobj->systype = nvr_systype_polo; + break; + case nvr_systype_woodfield: + pnvrobj->systype = nvr_systype_woodfield; + break; + default: + pnvrobj->systype = nvr_systype_unknown; + break; + } + } + + return(pnvrobj); +} + +/***********************************************************************/ +VOID nvr_delete_object() +{ + PNVR_OBJECT p = pnvrobj; + + if ((p == NULL) || (p != p->self)) + return; + + p->self = (PNVR_OBJECT)0; + + (void)nvr_free(p); + + pnvrobj = (PNVR_OBJECT)0; + + return; +} + +/***********************************************************************/ +STATUS_TYPE nvr_initialize_object(NVR_SYSTEM_TYPE systemtype) +{ + HEADER* hp; + +#ifdef KDB + DbgPrint("enter nvr_initialize_object\n"); +#endif /* KDB */ + + if (pnvrobj) + return(stat_exist); + + /* create object or get static address */ + if (!(pnvrobj = nvr_create_object(systemtype))) + return(stat_error); + + /* read the header from NVRAM and convert to little endian */ + nvr_read_nvram(pnvrobj); + + return(stat_ok); +} + +/***********************************************************************/ +VOID nvr_clear_nvram(PNVR_OBJECT p) +{ + ULONG i; + ULONG len; + + /* validate pointer */ + if ((p == NULL) || (p != p->self)) + return; + + len = NVSIZE; + switch (p->systype) { + case nvr_systype_polo: + case nvr_systype_woodfield: + len *= 2; + break; + case nvr_systype_powerstack: + case nvr_systype_sandalfoot: + break; + case nvr_systype_delmar: + default: + break; + } + + for (i = 0; i < len; i++) { + nvr_write(p->systype,i,0); + } + + return; +} + +/***********************************************************************/ +VOID nvr_destroy() +{ + NVR_SYSTEM_TYPE st; + + /* validate pointer */ + if ((pnvrobj == NULL) || (pnvrobj != pnvrobj->self)) + return; + + st = pnvrobj->systype; + + nvr_delete_object(); + nvr_initialize_object(st); + nvr_clear_nvram(pnvrobj); + nvr_delete_object(); + + nvr_initialize_object(st); + +#ifdef KDB + nvr_display_object(pnvrobj); + nvr_display_lemap(pnvrobj); + nvr_display_bemap(pnvrobj); +#endif /* KDB */ + + return; +} + +/* +*********************************************************************** +** Computation of CRCs must be done consistent with the approach +** taken by the Firmware (Dakota or Open FW). The algorithm for the +** following CRC routines (i.e., nvr_computecrc, nvr_calc1crc, +** nvr_calc2crc were obtained from the ESW group that develops +** Dakota FW +** +** If Dakota changes, then these routines may have to change also. +** +** 07.21.94 +*********************************************************************** +*/ + +#define rol(x,y) ( ( ((x)<<(y)) | ((x)>>(16 - (y))) ) & 0x0FFFF) +#define ror(x,y) ( ( ((x)>>(y)) | ((x)<<(16 - (y))) ) & 0x0FFFF) + +ULONG nvr_computecrc(ULONG oldcrc, UCHAR data) +{ + ULONG pd, crc; + + pd = ((oldcrc>>8) ^ data) << 8; + + crc = 0xFF00 & (oldcrc << 8); + crc |= pd >> 8; + crc ^= rol(pd,4) & 0xF00F; + crc ^= ror(pd,3) & 0x1FE0; + crc ^= pd & 0xF000; + crc ^= ror(pd,7) & 0x01E0; + return crc; +} + +USHORT nvr_calc1crc(PNVR_OBJECT p) +{ + ULONG ul; + ULONG i; + PUCHAR cp; + ULONG len1; + ULONG len2; + USHORT us; + + /* validate pointer */ + if ((p == NULL) || (p != p->self)) + return(0); + + ul = 0x0ffff; + + // do not include current Crc1/Crc2 in checksum + len1 = (sizeof(p->bhead->Size) + + sizeof(p->bhead->Version) + + sizeof(p->bhead->Revision)); + len2 = (ULONG) p->lhead->OSAreaAddress; + + + // calculate the area before Crc1/Crc2 in the header + for (cp = (PUCHAR)p->bhead, i = 0; i < len1; i++) + ul = nvr_computecrc(ul, cp[i]); + + // advance to calculate the area after Crc1, Crc2, and LastOS + // to include the region up to the OSArea + i += (sizeof(p->bhead->Crc1) + sizeof(p->bhead->Crc2)) + 1; + for (i = i; i < len2; i++) + ul = nvr_computecrc(ul, cp[i]); + + us = (USHORT)(ul & 0x0ffff); + + return(us); +} + +USHORT nvr_calc2crc(PNVR_OBJECT p) +{ + ULONG ul; + PUCHAR cp; + PUCHAR end; + + /* validate pointer */ + if ((p == NULL) || (p != p->self)) + return 0; + + ul = 0x0ffff; + + cp = (PUCHAR)((ULONG)p->bhead + (ULONG)p->lhead->ConfigAddress); + end = (PUCHAR)((ULONG)p->bhead + + (ULONG)(((ULONG)p->lhead->Size << 10) - 1)); + for (; cp < end; cp++) + ul = nvr_computecrc(ul, *cp); + + return((USHORT)(ul & 0x0ffff)); +} + +/* +*********************************************************************** +** Computation of CRCs must be done consistent with the approach +** taken by the Firmware (Dakota or Open FW). The algorithm for the +** above CRC routines (i.e., nvr_computecrc, nvr_calc1crc, +** nvr_calc2crc were obtained from the ESW group that develops +** Dakota FW +** +** 07.21.94 +*********************************************************************** +*/ + +/* +*********************************************************************** +** ----------- Methods Public to the higher layers of SW ------------- +** The methods below operate on the little endian section of the +** data structure internal to this file. Little endian is the internal +** (volatile RAM) representation of the NVRAM contents. All access to +** NVRAM data (variables, etc) are performed on this internal +** representation. When necessary, the internal representation is +** downloaded back to NVRAM. +*********************************************************************** +*/ + +VOID nvr_print_object() +{ +#ifdef KDB + nvr_display_object(pnvrobj); + nvr_display_lemap(pnvrobj); + nvr_display_bemap(pnvrobj); +#endif /* KDB */ + return; +} + +STATUS_TYPE nvr_find_OS_variable(PUCHAR var, PULONG ni, PULONG vi) +{ + PUCHAR lvar; + PUCHAR cp; + ULONG i; + PNVRAM_MAP little_nvrmap; + + if (*var == 0) + return(stat_error); + + if (!pnvrobj) + return(stat_error); + + little_nvrmap = (PNVRAM_MAP)pnvrobj->lend; + + i = 0; + while (TRUE) { + lvar = var; + *ni = i; + cp = (PUCHAR)((ULONG)little_nvrmap + + (ULONG)(little_nvrmap->Header.OSAreaAddress)); + + /* does the variable we want start at this index? */ + while (i < little_nvrmap->Header.OSAreaLength) { + /* break if mismatch */ + if (_toupr_(cp[i]) != _toupr_(*lvar)) + break; + lvar++; + i++; + } + + /* if we're at the end of OSArea and var has a match */ + if ((*lvar == 0) && (cp[i] == '=')) { + *vi = ++i; + return(stat_ok); + } + + /* no match - set index to start of the next variable */ + if (i >= little_nvrmap->Header.OSAreaLength) + return(stat_error); + while (cp[i++] != 0) { + if (i >= little_nvrmap->Header.OSAreaLength) + return(stat_error); + } + } +} + +STATUS_TYPE nvr_find_GE_variable(PUCHAR var, PULONG ni, PULONG vi) +{ + PUCHAR lvar; + PUCHAR cp; + ULONG i; + HEADER* lhp; + + if (*var == 0) + return(stat_error); + + if (!pnvrobj) + return(stat_error); + + lhp = (HEADER*)pnvrobj->lhead; + + i = 0; + while (TRUE) { + lvar = var; + *ni = i; + cp = (PUCHAR)((ULONG)lhp + (ULONG)(lhp->GEAddress)); + + /* does the variable we want start at this index? */ + while (i < lhp->GELength) { + /* break if mismatch */ + if (_toupr_(cp[i]) != _toupr_(*lvar)) + break; + lvar++; + i++; + } + + /* if we're at the end of GEArea and var has a match */ + if ((*lvar == 0) && (cp[i] == '=')) { + *vi = ++i; + return(stat_ok); + } + + /* no match - set index to start of the next variable */ + if (i >= lhp->GELength) + return(stat_error); + while (cp[i++] != 0) { + if (i >= lhp->GELength) + return(stat_error); + } + } +} + +PUCHAR nvr_get_OS_variable(PUCHAR vname) +{ + ULONG ni; + ULONG vi; + ULONG i; + PNVRAM_MAP little_nvrmap; + + if (!pnvrobj) + return((PUCHAR)NULL); + + if (nvr_find_OS_variable(vname, &ni, &vi) != stat_ok) + return((PUCHAR)NULL); + + little_nvrmap = (PNVRAM_MAP)pnvrobj->lend; + + for (i = 0; i < MAXIMUM_ENVIRONMENT_VALUE - 1; i++) { + if (little_nvrmap->OSArea[vi] == 0) + break; + _currentstring[i] = little_nvrmap->OSArea[vi++]; + } + _currentstring[i] = 0; + + return(_currentstring); +} + +PUCHAR nvr_get_GE_variable(PUCHAR vname) +{ + ULONG ni; + ULONG vi; + ULONG i; + PUCHAR cp; + HEADER* lhp; + + if (!pnvrobj) + return((PUCHAR)NULL); + + if (nvr_find_GE_variable(vname, &ni, &vi) != stat_ok) + return((PUCHAR)NULL); + + lhp = (HEADER*)pnvrobj->lhead; + cp = (PUCHAR)((ULONG)lhp + (ULONG)lhp->GEAddress); + + for (i = 0; i < MAXIMUM_ENVIRONMENT_VALUE - 1; i++) { + if (cp[vi] == 0) { + break; + } + _currentstring[i] = cp[vi++]; + } + _currentstring[i] = 0; + +#ifdef KDB +DbgPrint("get_GE vname: '%s' value: '%s'\n", vname, _currentstring); +#endif /* KDB */ + + return(_currentstring); +} + +STATUS_TYPE nvr_set_OS_variable(PUCHAR vname, PUCHAR value) +{ + ULONG nameindex; + ULONG valueindex; + ULONG eos; + PUCHAR str; + ULONG count; + CHAR c; + PUCHAR aptr; + HEADER* lhp; + + if ((vname == 0) || (value == 0)) + return(stat_error); + + if (*vname == 0) + return(stat_error); + + if (!pnvrobj) + return(stat_error); + + lhp = (HEADER*)pnvrobj->lhead; + +#ifdef KDB +DbgPrint("OS vname: '%s' value: '%s'\n", vname, value); +#endif /* KDB */ + + /* initialize pointer to OS area */ + aptr = (PUCHAR)((ULONG)lhp + (ULONG)lhp->OSAreaAddress); + + // find the end of the used OS space by looking for + // the first non-null character from the top + eos = lhp->OSAreaLength - 1; + while (aptr[--eos] == 0) { + if (eos == 0) + break; + } + + // position eos to the first new character, unless + // environment space is empty + if (eos != 0) + eos += 2; + + // find out if the variable already has a value + count = lhp->OSAreaLength - eos; + if (nvr_find_OS_variable(vname, &nameindex, &valueindex) == stat_ok) { + // count free space + // start with the free area at the top and add + // the old nameindex value + for (str = &(aptr[valueindex]); *str != 0; str++) + count++; + + // if free area is not large enough to handle new value return error + for (str = value; *str != 0; str++) { + if (count-- == 0) + return(stat_error); + } + + // pack strings + // first move valueindex to the end of the value + while (aptr[valueindex++] != 0) + ; + + // now move everything to where the variable starts + // covering up the old name/value pair + while (valueindex < eos) { + c = aptr[valueindex++]; + aptr[nameindex++] = c; + } + + // adjust new top of environment + eos = nameindex; + + // zero to the end of OS area + while (nameindex < lhp->OSAreaLength) + aptr[nameindex++] = 0; + } + else { + // variable is new + // if free area is not large enough to handle new value return error + for (str = value; *str != 0; str++) { + if (count-- == 0) + return(stat_error); + } + } + + /* if value is null, we have removed the variable */ + if (*value) { + // insert new name, converting to upper case. + while (*vname != 0) { + aptr[eos++] = _toupr_(*vname); + vname++; + } + aptr[eos++] = '='; + + // insert new value + while (*value != 0) { + aptr[eos++] = *value; + value++; + } + } + + nvr_write_OSArea(pnvrobj); + + return(stat_ok); +} + +STATUS_TYPE nvr_set_GE_variable(PUCHAR vname, PUCHAR value) +{ + ULONG nameindex; + ULONG valueindex; + ULONG toe; + PUCHAR str; + ULONG count; + CHAR c; + PUCHAR aptr; + HEADER* lhp; + + if (vname == 0) + return(stat_error); + + if (*vname == 0) + return(stat_error); + + if (!pnvrobj) + return(stat_error); + + lhp = (HEADER*)pnvrobj->lhead; + +#ifdef KDB +DbgPrint("set_GE vname: '%s' value: '%s'\n", vname, value); +#endif /* KDB */ + + /* initialize pointer to OS area */ + aptr = (PUCHAR)((ULONG)lhp + (ULONG)lhp->GEAddress); + + /* find the top of the used environment space by looking for */ + /* the first non-null character from the top */ + toe = lhp->GELength - 1; + + aptr = (PUCHAR)((ULONG)lhp + (ULONG)lhp->GEAddress); + while (aptr[--toe] == 0) { + if (toe == 0) + break; + } + + /* adjust toe to the first new character, unless */ + /* environment space is empty */ + if (toe != 0) + toe += 2; + + /* find out if the variable already has a value */ + count = lhp->GELength - toe; + if (nvr_find_GE_variable(vname, &nameindex, &valueindex) == stat_ok) { + /* count free space */ + /* start with the free area at the top and add */ + /* the old nameindex value */ + for (str = &(aptr[valueindex]); *str != 0; str++) + count++; + + /* if free area is not large enough to handle new value return error */ + if (value) { + for (str = value; *str != 0; str++) { + if (count-- == 0) + return(stat_error); + } + } + + /* pack strings */ + /* first move valueindex to the end of the value */ + while (aptr[valueindex++] != 0) + ; + + /* now move everything to where the variable starts */ + /* covering up the old name/value pair */ + while (valueindex < toe) { + c = aptr[valueindex++]; + aptr[nameindex++] = c; + } + + /* adjust new top of environment */ + toe = nameindex; + + /* zero to the end of GE area */ + while (nameindex < lhp->GELength) + aptr[nameindex++] = 0; + } + else { + /* variable is new */ + /* if free area is not large enough to handle new value return error */ + if (value) { + for (str = value; *str != 0; str++) { + if (count-- == 0) + return(stat_error); + } + } + } + + /* if value is null or is a pointer to a 0 */ + /* the variable has been removed */ + if ((value) && (*value)) { + /* insert new name, converting to upper case */ + while (*vname != 0) { + aptr[toe] = _toupr_(*vname); + vname++; + toe++; + } + aptr[toe++] = '='; + + /* insert new value */ + while (*value != 0) { + aptr[toe] = *value; + value++; + toe++; + } + } + + nvr_write_GEArea(pnvrobj); + + return(stat_ok); +} + +PUCHAR nvr_fetch_GE() +{ + ULONG i; + ULONG toe; + PNVRAM_MAP little_nvrmap; + + if (!pnvrobj) + return NULL; + + little_nvrmap = (NVRAM_MAP *)pnvrobj->lend; + + // initialize hold buffer to zeros + for (i = 0; i < little_nvrmap->Header.GELength; i++) + _currentfetch[i] = 0; + + // find the top of the used environment space by looking for + // the first non-null character from the top + toe = little_nvrmap->Header.GELength - 1; + while ((little_nvrmap->GEArea[--toe]) == 0) { + if (toe == 0) + break; + } + + // toe contains last index of GE + if (toe == 0) + return(_currentfetch); + + // copy from GE to hold buffer + for (i = 0; ((i <= toe) && (i < MAXNVRFETCH)); i++) + _currentfetch[i] = little_nvrmap->GEArea[i]; + + return(_currentfetch); +} + +PUCHAR nvr_fetch_OS() +{ + ULONG i; + ULONG toe; + PNVRAM_MAP little_nvrmap; + + if (!pnvrobj) + return NULL; + + little_nvrmap = (NVRAM_MAP *)pnvrobj->lend; + + // initialize the hold buffer to zeros + for (i = 0; i < little_nvrmap->Header.OSAreaLength; i++) + _currentfetch[i] = 0; + + // find the top of the used environment space by looking for + // the first non-null character from the top + toe = little_nvrmap->Header.OSAreaLength - 1; + while ((little_nvrmap->OSArea[--toe]) == 0) { + if (toe == 0) + break; + } + + // toe contains last index of OS + if (toe == 0) + return(_currentfetch); + + // copy from OS to hold buffer + for (i = 0; ((i <= toe) && (i < MAXNVRFETCH)); i++) + _currentfetch[i] = little_nvrmap->OSArea[i]; + + return(_currentfetch); +} + +PUCHAR nvr_fetch_CF() +{ + ULONG i; + PNVRAM_MAP little_nvrmap; + + if (!pnvrobj) + return NULL; + + little_nvrmap = (NVRAM_MAP *)pnvrobj->lend; + + /* initialize the hold buffer to zeros */ + for (i = 0; i < MAXNVRFETCH; i++) + _currentfetch[i] = 0; + + /* copy from Config to hold buffer */ + for (i = 0; i < little_nvrmap->Header.ConfigLength; i++) + _currentfetch[i] = little_nvrmap->ConfigArea[i]; + + return(_currentfetch); +} + +/* +*********************************************************************** +** ----------- Methods Public to the higher layers of SW ------------- +** The methods above operate on the little endian section of the +** data structure internal to this file. Little endian is the internal +** (volatile RAM) representation of the NVRAM contents. All access to +** NVRAM data (variables, etc) are performed on this internal +** representation. When necessary, the internal representation is +** downloaded back to NVRAM. +*********************************************************************** +*/ + +#ifdef KDB +/* +*********************************************************************** +** The methods below are used in development and debug. +*********************************************************************** +*/ + +VOID nvr_display_object(PNVR_OBJECT p) +{ + PUCHAR cp; + int len; + UCHAR tmp; + PNVRAM_MAP mp; + + /* validate pointer */ + if ((p == NULL) || (p != p->self)) + return; + + DbgPrint(" ---- ---- INTERNAL DISPLAY ---- ----\n\r"); + DbgPrint(" Object Addr: 0x%08lx\n\r",(ULONG)p->self); + switch (p->systype) { + case nvr_systype_powerstack: + DbgPrint(" System Type: PowerStack\n\r"); + break; + case nvr_systype_sandalfoot: + DbgPrint(" System Type: Sandalfoot\n\r"); + break; + case nvr_systype_polo: + DbgPrint(" System Type: Polo\n\r"); + break; + case nvr_systype_woodfield: + DbgPrint(" System Type: Woodfield\n\r"); + break; + case nvr_systype_delmar: + DbgPrint(" System Type: Delmar\n\r"); + break; + default: + DbgPrint(" System Type: Unknown\n\r"); + break; + } + DbgPrint(" BE Header addr: 0x%08lx\n\r",(ULONG)p->bhead); + DbgPrint(" BE Map addr: 0x%08lx\n\r",(ULONG)p->bend); + DbgPrint(" LE Header addr: 0x%08lx\n\r",(ULONG)p->lhead); + DbgPrint(" LE Map addr: 0x%08lx\n\r",(ULONG)p->lend); + DbgPrint(" ---- ---- INTERNAL DISPLAY ---- ----\n\r"); + + return; +} + +VOID nvr_display_lemap(PNVR_OBJECT p) +{ + PUCHAR cp; + PUCHAR max; + UCHAR tmp; + + /* validate pointer */ + if ((p == NULL) || (p != p->self)) + return; + + DbgPrint(" -------- ---- ---- ---- ---- LITTLE DISPLAY\n\r"); + DbgPrint(" NVR Size: 0x%04xK (%dK)", (int)p->lhead->Size, + (int)p->lhead->Size); + DbgPrint(" Version: 0x%02x Revision: 0x%02x\n\r", + (int)p->lhead->Version, (int)p->lhead->Revision); + DbgPrint(" Crc1: 0x%04x Crc2: 0x%04x\n\r", + (int)p->lhead->Crc1, (int)p->lhead->Crc2); + DbgPrint(" NVR Endian: '%c'\n\r",p->lhead->Endian); + + tmp = p->lhead->Security.Serial[15]; + p->lhead->Security.Serial[15] = 0; + DbgPrint(" NVR Serial: '%s'\n\r",p->lhead->Security.Serial); + p->lhead->Security.Serial[15] = tmp; + + DbgPrint(" GEAddress: 0x%08lx GELength: 0x%08lx\n\r", + (ULONG)p->lhead->GEAddress, (ULONG)p->lhead->GELength); + cp = (PUCHAR)((ULONG)p->lhead + (ULONG)p->lhead->GEAddress); + max = (PUCHAR)((ULONG)p->lhead + (ULONG)p->lhead->GEAddress + + (ULONG)p->lhead->GELength); + while ((*cp) && (cp < max)) { + DbgPrint(" '%s'\n\r", cp); + cp += (strlen(cp) + 1); + } + + DbgPrint(" OSAreaAddress: 0x%08lx OSAreaLength: 0x%08lx\n\r", + (ULONG)p->lhead->OSAreaAddress, (ULONG)p->lhead->OSAreaLength); + cp = (PUCHAR)((ULONG)p->lhead + (ULONG)p->lhead->OSAreaAddress); + max = (PUCHAR)((ULONG)p->lhead + (ULONG)p->lhead->OSAreaAddress + + (ULONG)p->lhead->OSAreaLength); + while ((*cp) && (cp < max)) { + DbgPrint(" '%s'\n\r", cp); + cp += (strlen(cp) + 1); + } + + DbgPrint(" ConfigAddress: 0x%08lx ConfigLength: 0x%08lx Count: 0x%08lx\n\r", + (ULONG)p->lhead->ConfigAddress, (ULONG)p->lhead->ConfigLength, + (ULONG)p->lhead->ConfigCount); + DbgPrint(" -------- ---- ---- ---- ---- LITTLE DISPLAY\n\r"); + + return; +} + +VOID nvr_display_bemap(PNVR_OBJECT p) +{ + PUCHAR cp; + PUCHAR max; + UCHAR tmp; + PNVRAM_MAP mp; + HEADER* hp; + + /* validate pointer */ + if ((p == NULL) || (p != p->self)) + return; + + mp = p->bend; + hp = p->bhead; + + DbgPrint(" ---- ---- BIG DISPLAY ---- ----\n\r"); + DbgPrint(" NVR Size: 0x%04xK (%dK)", (int)mp->Header.Size, + (int)mp->Header.Size); + DbgPrint(" Version: 0x%02x Revision: 0x%02x\n\r", + (int)mp->Header.Version, (int)mp->Header.Revision); + DbgPrint(" Crc1: 0x%04x Crc2: 0x%04x\n\r", + (int)mp->Header.Crc1, (int)mp->Header.Crc2); + DbgPrint(" NVR Endian: '%c'\n\r",mp->Header.Endian); + + tmp = mp->Header.Security.Serial[15]; + mp->Header.Security.Serial[15] = 0; + DbgPrint(" NVR Serial: '%s'\n\r",mp->Header.Security.Serial); + mp->Header.Security.Serial[15] = tmp; + + DbgPrint(" GEAddress: 0x%08lx GELength: 0x%08lx\n\r", + (ULONG)hp->GEAddress, (ULONG)hp->GELength); + cp = (PUCHAR)((ULONG)hp + _ppc_longswap((ULONG)hp->GEAddress)); + max = (PUCHAR)((ULONG)cp + _ppc_longswap((ULONG)hp->GELength)); + while ((*cp) && (cp < max)) { + DbgPrint(" '%s'\n\r", cp); + cp += (strlen(cp) + 1); + } + + DbgPrint(" OSAreaAddress: 0x%08lx OSAreaLength: 0x%08lx\n\r", + (ULONG)hp->OSAreaAddress, (ULONG)hp->OSAreaLength); + cp = (PUCHAR)((ULONG)hp + _ppc_longswap((ULONG)hp->OSAreaAddress)); + max = (PUCHAR)((ULONG)cp + _ppc_longswap((ULONG)hp->OSAreaLength)); + while ((*cp) && (cp < max)) { + DbgPrint(" '%s'\n\r", cp); + cp += (strlen(cp) + 1); + } + + DbgPrint(" ConfigAddress: 0x%08lx ConfigLength: 0x%08lx Count: 0x%08lx\n\r", + (ULONG)hp->ConfigAddress, (ULONG)hp->ConfigLength, + (ULONG)hp->ConfigCount); + DbgPrint(" ---- ---- BIG DISPLAY ---- ----\n\r"); + + return; +} + +VOID nvr_test_setvar(VOID) +{ + DbgPrint("\n\r"); + DbgPrint("--------- VARIABLE SET TEST\n\r"); + nvr_display_lemap(pnvrobj); + DbgPrint("---------\n\r"); + + (VOID)nvr_set_GE_variable("GESLUG0","this is it"); + (VOID)nvr_set_GE_variable("GESLUG1","NO: this is it"); + (VOID)nvr_set_GE_variable("GESLUG2","I beg your pardon! This is it"); + + (VOID)nvr_set_OS_variable("OSSLUG0","multi(0)scsi(0)"); + (VOID)nvr_set_OS_variable("OSSLUG1","multi(0)scsi(1)"); + (VOID)nvr_set_OS_variable("OSSLUG2", + "multi(0)scsi(0)disk(6)rdisk(0)partition(1)"); + nvr_display_lemap(pnvrobj); + + DbgPrint("--------- VARIABLE SET TEST\n\r"); + + return; +} + +VOID nvr_test_object(NVR_SYSTEM_TYPE systemtype) +{ + PUCHAR cp; + + nvr_initialize_object(systemtype); + + nvr_display_object(pnvrobj); + nvr_display_lemap(pnvrobj); + nvr_display_bemap(pnvrobj); + +/*************************** + cp = nvr_get_GE_variable("SYSTEMPARTITION"); + if (cp) { + if (*cp == 0) + DbgPrint("nvr_test_object: SYSTEMPARTITION=-value zero-\n",cp); + else + DbgPrint("nvr_test_object: SYSTEMPARTITION='%s'\n",cp); + } + else + DbgPrint("nvr_test_object: SYSTEMPARTITION=-pointer NULL-\n"); + + cp = nvr_get_GE_variable("DOG000111"); + if (cp) { + if (*cp == 0) + DbgPrint("nvr_test_object: DOG000111=-value zero-\n",cp); + else + DbgPrint("nvr_test_object: DOG000111='%s'\n",cp); + } + else + DbgPrint("nvr_test_object: DOG000111=-pointer NULL-\n"); + + DbgBreakPoint(); + nvr_test_setvar(); + DbgBreakPoint(); +***************************/ + +/*************************** + DbgPrint("--------- CLEARING NVRAM\n"); + if (!(pnvrobj = nvr_create_object(systemtype))) + return; + nvr_clear_nvram(pnvrobj); + nvr_delete_object(); + DbgPrint("--------- CLEARED NVRAM\n"); + DbgBreakPoint(); +***************************/ + +/*************************** + DbgPrint("--------- REREAD NVRAM \n\r"); + DbgPrint("---------\n"); + DbgPrint("---------\n"); + nvr_initialize_object(systemtype); + DbgPrint("nvr_calc1crc: 0x%08x\n",(int)nvr_calc1crc(pnvrobj)); + DbgPrint("nvr_calc2crc: 0x%08x\n",(int)nvr_calc2crc(pnvrobj)); + nvr_display_lemap(pnvrobj); + nvr_display_bemap(pnvrobj); + DbgPrint("--- SETTING VARS\n"); + (VOID)nvr_set_GE_variable("GESLUG0","this is it"); + (VOID)nvr_set_GE_variable("GESLUG1"," -------- this is it --------"); + (VOID)nvr_set_OS_variable("OSSLUG0","multi(0)scsi(0)"); + (VOID)nvr_set_OS_variable("OSSLUG1","multi(1)scsi(1)"); + nvr_display_lemap(pnvrobj); + nvr_display_bemap(pnvrobj); + (VOID)nvr_set_GE_variable("GESLUG0",""); + nvr_display_lemap(pnvrobj); + + DbgPrint("---------\n"); + DbgPrint("---------\n"); + DbgPrint("--------- REREAD NVRAM \n\r"); + DbgBreakPoint(); + +***************************/ + + return; +} +#endif /* KDB */ diff --git a/private/ntos/nthals/haleagle/ppc/fwnvr.h b/private/ntos/nthals/haleagle/ppc/fwnvr.h new file mode 100644 index 000000000..568d83f95 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/fwnvr.h @@ -0,0 +1,37 @@ +#ifndef _FWNVR_H +#define _FWNVR_H + +typedef enum _nvr_system_type { + nvr_systype_null = 0x00, + nvr_systype_unknown = 0x01, + nvr_systype_sandalfoot = 0x02, + nvr_systype_polo = 0x04, + nvr_systype_woodfield = 0x08, + nvr_systype_delmar = 0x10, + nvr_systype_bigbend = 0x20, + nvr_systype_powerstack = 0x40, + nvr_systype_last = 0x80 + } NVR_SYSTEM_TYPE; + +STATUS_TYPE nvr_initialize_object(NVR_SYSTEM_TYPE); +VOID nvr_delete_object(VOID); +VOID nvr_destroy(VOID); +STATUS_TYPE nvr_find_GE_variable(PUCHAR,PULONG,PULONG); +STATUS_TYPE nvr_set_GE_variable(PUCHAR,PUCHAR); +STATUS_TYPE nvr_find_OS_variable(PUCHAR,PULONG,PULONG); +STATUS_TYPE nvr_set_OS_variable(PUCHAR,PUCHAR); + +PUCHAR nvr_get_GE_variable(PUCHAR); +PUCHAR nvr_get_OS_variable(PUCHAR); +PUCHAR nvr_fetch_GE(VOID); +PUCHAR nvr_fetch_OS(VOID); +PUCHAR nvr_fetch_CF(VOID); + +#ifdef KDB +VOID nvr_print_object(VOID); +VOID nvr_test_object(NVR_SYSTEM_TYPE); +#endif /* KDB */ + +#define MAXIMUM_ENVIRONMENT_VALUE 256 + +#endif /* _FWNVR_H */ diff --git a/private/ntos/nthals/haleagle/ppc/fwstatus.h b/private/ntos/nthals/haleagle/ppc/fwstatus.h new file mode 100644 index 000000000..fd09e6363 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/fwstatus.h @@ -0,0 +1,17 @@ +#ifndef _FWSTATUS_H_ +#define _FWSTATUS_H_ + +typedef enum _status_type { + stat_ok = 0, + stat_warning = 1, + stat_exist = 2, + stat_error = 3, + stat_badptr = 4, + stat_notexist = 5, + stat_noentry = 6, + stat_checksum = 7, + stat_badlength = 8, + stat_last = 0x40 + } STATUS_TYPE; + +#endif /* _FWSTATUS_H_ */ diff --git a/private/ntos/nthals/haleagle/ppc/halp.h b/private/ntos/nthals/haleagle/ppc/halp.h new file mode 100644 index 000000000..ad74517ac --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/halp.h @@ -0,0 +1,239 @@ +/*++ BUILD Version: 0003 // Increment this if a change has global effects + +Copyright (C) 1991-1995 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: + + Jim Wooldridge (jimw@austin.vnet.ibm.com) Initial PowerPC port + + Added PPC specific includes + Changed paramaters to HalpProfileInterrupt + Added function prototype for HalpWriteCompareRegisterAndClear() + Added include for ppcdef.h + +--*/ + +#ifndef _HALP_ +#define _HALP_ + +#if defined(NT_UP) + +#undef NT_UP + +#endif + +#include "nthal.h" +#include "hal.h" + +#include "ppcdef.h" +#include "pxhalp.h" + +#ifndef _HALI_ +#include "..\inc\hali.h" +#endif + + + + +// +// Resource usage information +// + +#define MAXIMUM_IDTVECTOR 255 + +typedef struct { + UCHAR Flags; + KIRQL Irql; + UCHAR BusReleativeVector; +} IDTUsage; + +typedef struct _HalAddressUsage{ + struct _HalAddressUsage *Next; + CM_RESOURCE_TYPE Type; // Port or Memory + UCHAR Flags; // same as IDTUsage.Flags + struct { + ULONG Start; + USHORT Length; + } Element[]; +} ADDRESS_USAGE; + +#define IDTOwned 0x01 // IDT is not available for others +#define InterruptLatched 0x02 // Level or Latched +#define InternalUsage 0x11 // Report usage on internal bus +#define DeviceUsage 0x21 // Report usage on device bus + +extern IDTUsage HalpIDTUsage[]; +extern ADDRESS_USAGE *HalpAddressUsageList; + +#define HalpRegisterAddressUsage(a) \ + (a)->Next = HalpAddressUsageList, HalpAddressUsageList = (a); + + +#define HalpGetProcessorVersion() KeGetPvr() + +#define HalpEnableInterrupts() _enable() +#define HalpDisableInterrupts() _disable() + +#define KeFlushWriteBuffer() __builtin_eieio() + +// +// Bus handlers +// + + +PBUS_HANDLER HalpAllocateBusHandler ( + IN INTERFACE_TYPE InterfaceType, + IN BUS_DATA_TYPE BusDataType, + IN ULONG BusNumber, + IN BUS_DATA_TYPE ParentBusDataType, + IN ULONG ParentBusNumber, + IN ULONG BusSpecificData + ); + +#define HalpAllocateConfigSpace HalpAllocateBusHandler + +#define SPRANGEPOOL NonPagedPool // for now, until crashdump is fixed +#define HalpHandlerForBus HaliHandlerForBus +#define HalpSetBusHandlerParent(c,p) (c)->ParentHandler = p; + + +// +// Define function prototypes. +// + +BOOLEAN +HalpGrowMapBuffers( + PADAPTER_OBJECT AdapterObject, + ULONG Amount + ); + +PADAPTER_OBJECT +HalpAllocateAdapter( + IN ULONG MapRegistersPerChannel, + IN PVOID AdapterBaseVa, + IN PVOID MapRegisterBase + ); + + +BOOLEAN +HalpCalibrateStall ( + VOID + ); + +BOOLEAN +HalpInitializeInterrupts ( + VOID + ); + +VOID +HalpIpiInterrupt ( + VOID + ); + +BOOLEAN +HalpInitializeDisplay ( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ); + +BOOLEAN +HalpMapIoSpace ( + VOID + ); + +ULONG +HalpTranslatePciSlotNumber ( + ULONG, + ULONG + ); + +BOOLEAN +HalpInitPciIsaBridge ( + VOID + ); + +VOID +HalpHandleIoError ( + VOID + ); + +BOOLEAN +HalpInitPlanar ( + VOID + ); + +VOID +HalpHandleMemoryError( + VOID + ); + +BOOLEAN +HalpHandleProfileInterrupt ( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext, + IN PVOID TrapFrame + ); + + +BOOLEAN +HalpEnableInterruptHandler ( + IN PKINTERRUPT Interrupt, + IN PKSERVICE_ROUTINE ServiceRoutine, + IN PVOID ServiceContext, + IN PKSPIN_LOCK SpinLock OPTIONAL, + IN ULONG Vector, + IN KIRQL Irql, + IN KIRQL SynchronizeIrql, + IN KINTERRUPT_MODE InterruptMode, + IN BOOLEAN ShareVector, + IN CCHAR ProcessorNumber, + IN BOOLEAN FloatingSave, + IN UCHAR ReportFlags, + IN KIRQL BusVector + ); + + +VOID +HalpRegisterVector ( + IN UCHAR ReportFlags, + IN ULONG BusInterruptVector, + IN ULONG SystemInterruptVector, + IN KIRQL SystemIrql + ); + +VOID +HalpReportResourceUsage ( + IN PUNICODE_STRING HalName, + IN INTERFACE_TYPE DeviceInterfaceToUse + ); + +// +// Define external references. +// + +extern KSPIN_LOCK HalpBeepLock; +extern KSPIN_LOCK HalpDisplayAdapterLock; +extern KSPIN_LOCK HalpSystemInterruptLock; +extern KAFFINITY HalpIsaBusAffinity; +extern ULONG HalpProfileCount; +extern ULONG HalpCurrentTimeIncrement; +extern ULONG HalpNextTimeIncrement; +extern ULONG HalpNewTimeIncrement; + + +#define IRQ_VALID 0x01 +#define IRQ_PREFERRED 0x02 + +#endif // _HALP_ diff --git a/private/ntos/nthals/haleagle/ppc/mk48tdc.h b/private/ntos/nthals/haleagle/ppc/mk48tdc.h new file mode 100644 index 000000000..c98179731 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/mk48tdc.h @@ -0,0 +1,68 @@ +/*++ +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + mk48tdc.h + +Abstract: + + This module is the header file that describes hardware structure + for the realtime clock on the Comet (PowerPC 603/604) platform. + + This module was taken from the jazzrtc.h file and renamed. + +Original Author: + + David N. Cutler (davec) 3-May-1991 + +Revision History: + +Who When What +--- -------- ----------------------------------------------- +dgh 07/13/94 Redefined the TODC registers for the MK48T18 chip. +dgh 07/22/94 Update file name in header comment. +dgh 08/03/94 Redefined virtual address of RTC and NVRAM. +dgh 08/08/94 Don't use virtual addresses for RTC and NVRAM, use + offsets instead. Actual virtual address will be in + the HalpNvramBaseAddr variable. +kjr 10/18/94 Changes to support Revision B Comet motherboard. + Remove HalpNvramBaseAddr and use new NVRAM address + and data port. + +--*/ + +#ifndef _MK48TDC +#define _MK48TDC + + +typedef struct _NVRAM_CONTROL { + UCHAR Reserved0[0x74]; + UCHAR NvramIndexLo; // Offset 0x74 + UCHAR NvramIndexHi; // Offset 0x75 + UCHAR Reserved2[1]; + UCHAR NvramData; // Offset 0x77 +} NVRAM_CONTROL, *PNVRAM_CONTROL; + +// +// Define Realtime Clock register numbers +// for the MK48T18 TODC Chip. +// +#define TODC_CONTROL 0 // TODC Control Register +#define TODC_SECOND 1 // second of minute [0..59] +#define TODC_MINUTE 2 // minute of hour [0..59] +#define TODC_HOUR 3 // hour of day [0..23] +#define TODC_DAY_OF_WEEK 4 // day of week [1..7] +#define TODC_DAY_OF_MONTH 5 // day of month [1..31] +#define TODC_MONTH 6 // month of year [1..12] +#define TODC_YEAR 7 // year [00..99] + + +// +// Comet NVRAM/RTC Mapping +// +#define TODC_OFFSET 0x9ff8 // offset of RTC +#define NVR_OFFSET 0x8000 // offset of NVRAM + + +#endif // MK48TDC diff --git a/private/ntos/nthals/haleagle/ppc/mk48time.c b/private/ntos/nthals/haleagle/ppc/mk48time.c new file mode 100644 index 000000000..fe0ccf00d --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/mk48time.c @@ -0,0 +1,431 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +contains copyrighted material. Use of this file is restricted +by the provisions of a Motorola Software License Agreement. + +Module Name: + + mk48time.c + +Abstract: + + This module implements the HAL set/query realtime clock routines for + a PowerPC system using the MK48T18 Clock Chip. + +Original Author: + + David N. Cutler (davec) 5-May-1991 + +Environment: + + Kernel mode + +Revision History: + +Who When What +--- -------- ----------------------------------------------- +dgh 07/20/94 Created from pxtime.c and modified for MK48T18 chip. +dgh 07/22/94 Fixed typo of HalpReadRawClockRegister. +dgh 07/29/94 Don't run the day-of-week value through the BCD + conversion when reading the clock. Also mask it + to 3-bits. +dgh 08/08/94 Compute RTC location from HalpNvramBaseAddr and the + RTC offset. +dgh 08/09/94 HalQueryRealTimeClock: Forgot to restart the clock + after reading it. +kjr 10/18/94 Changes for Revision B Comet Mother Board. Remove + HalpNvramBaseAddr and use new NVRAM address and data + port. + +--*/ + +#include "halp.h" +#include "mk48tdc.h" +#include "eisa.h" + +#define WRITE 0x80 // Stop update while writing control bit +#define READ 0x40 // Stop updating while reading control bit +#define STOP 0x80 // Clock is stopped bit + +extern PVOID HalpIoControlBase; +#define RTC_BASE (TODC_OFFSET) +#define NVRAM ((PNVRAM_CONTROL) HalpIoControlBase) + +//*************************************************************************** +// Time of Day Clock registers for the MK48T18 chip can be viewed as an +// array of bytes (UCHARs) where: +// +// Address of Real Time Clock Register bitmap of registers +// ----------------------------------------------------------------------- +// TODC_OFFSET + 0: clock control/calibration reg. [W R S - - - - -] +// TODC_OFFSET + 1: seconds register (00-59) [P - - - - - - -] +// TODC_OFFSET + 2: minutes register (00-59) [0 - - - - - - -] +// TODC_OFFSET + 3: hours register (00-23) [0 0 - - - - - -] +// TODC_OFFSET + 4: day-of-week register (01-07) [0 F 0 0 0 - - -] +// TODC_OFFSET + 5: day-of-month register (01-31) [0 0 - - - - - -] +// TODC_OFFSET + 6: month register (01-12) [0 0 0 - - - - -] +// TODC_OFFSET + 7: year register (00-99) [- - - - - - - -] +// W=write, R=read, S=sign, P=stop +// F=frequency test. +// +// NOTE: Values in the TODC registers are in BCD format + + +// +// Define forward referenced procedure prototypes. +// + +static UCHAR +HalpReadRawClockRegister ( + UCHAR Register + ); + +static VOID +HalpWriteRawClockRegister ( + UCHAR Register, + UCHAR Value + ); + +static UCHAR +HalpReadClockRegister ( + UCHAR Register + ); + +static VOID +HalpWriteClockRegister ( + UCHAR Register, + UCHAR Value + ); + +BOOLEAN +HalQueryRealTimeClockMk ( + 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. + // + // NOTE: It isn't possible to test this clock chip to determine if + // the battery is still running or not. So we check the STOP + // bit and if set, then we return FALSE. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + DataByte = HalpReadRawClockRegister(TODC_SECOND); + if (!(DataByte & STOP)) { + + // + // Clock is running. + // Wait until the realtime clock is not being updated. + // + + do { + DataByte = HalpReadRawClockRegister(TODC_CONTROL); + } while (DataByte & WRITE); + + // + // First stop the clock from being updated while we read it. + // + DataByte = HalpReadRawClockRegister(TODC_CONTROL); + DataByte |= READ; + HalpWriteRawClockRegister(TODC_CONTROL, DataByte); + + // + // Read the realtime clock values. + // + + TimeFields->Year = 1900 + (CSHORT)HalpReadClockRegister(TODC_YEAR); + if (TimeFields->Year < 1980) TimeFields->Year += 100; + + TimeFields->Month = (CSHORT)HalpReadClockRegister(TODC_MONTH); + TimeFields->Day = (CSHORT)HalpReadClockRegister(TODC_DAY_OF_MONTH); + TimeFields->Weekday = (CSHORT)HalpReadClockRegister(TODC_DAY_OF_WEEK) - 1; + TimeFields->Hour = (CSHORT)HalpReadClockRegister(TODC_HOUR); + TimeFields->Minute = (CSHORT)HalpReadClockRegister(TODC_MINUTE); + TimeFields->Second = (CSHORT)HalpReadClockRegister(TODC_SECOND); + TimeFields->Milliseconds = 0; + + // + // Now restart the clock + // + DataByte = HalpReadRawClockRegister(TODC_CONTROL); + DataByte &= ~READ; + HalpWriteRawClockRegister(TODC_CONTROL, DataByte); + + KeLowerIrql(OldIrql); + return TRUE; + + } else { + KeLowerIrql(OldIrql); + return FALSE; + } +} + +BOOLEAN +HalSetRealTimeClockMk ( + 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. + // + // NOTE: We can't determine if the battery is running or not on + // this clock chip. So, instead we check the STOP bit and + // if set, then we treat this as the same condition and + // return FALSE. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + DataByte = HalpReadRawClockRegister(TODC_SECOND); + if (!(DataByte & STOP)) { + + // + // Clock is running. + // Set the realtime clock to stop updating while we set + // the time. + // + + + DataByte = HalpReadRawClockRegister(TODC_CONTROL); + DataByte |= WRITE; + HalpWriteRawClockRegister(TODC_CONTROL, DataByte); + + // + // Write the realtime clock values. + // + + if (TimeFields->Year > 1999) + HalpWriteClockRegister(TODC_YEAR, (UCHAR)(TimeFields->Year - 2000)); + else + HalpWriteClockRegister(TODC_YEAR, (UCHAR)(TimeFields->Year - 1900)); + + HalpWriteClockRegister(TODC_MONTH, (UCHAR)TimeFields->Month); + HalpWriteClockRegister(TODC_DAY_OF_MONTH, (UCHAR)TimeFields->Day); + HalpWriteClockRegister(TODC_DAY_OF_WEEK, (UCHAR)(TimeFields->Weekday + 1)); + HalpWriteClockRegister(TODC_HOUR, (UCHAR)TimeFields->Hour); + HalpWriteClockRegister(TODC_MINUTE, (UCHAR)TimeFields->Minute); + HalpWriteClockRegister(TODC_SECOND, (UCHAR)TimeFields->Second); + + // + // Set the realtime clock control to resume updating the time. + // + + DataByte = HalpReadRawClockRegister(TODC_CONTROL); + DataByte &= ~WRITE; + HalpWriteRawClockRegister(TODC_CONTROL, DataByte); + + + KeLowerIrql(OldIrql); + return TRUE; + + } else { + KeLowerIrql(OldIrql); + return FALSE; + } +} + +static UCHAR +HalpReadRawClockRegister ( + 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. + +--*/ + +{ + // + // Read the specified Register from the Real Time Clock. + // + WRITE_REGISTER_UCHAR (&NVRAM->NvramIndexLo, (RTC_BASE + Register) & 0xFF); + WRITE_REGISTER_UCHAR (&NVRAM->NvramIndexHi, (RTC_BASE + Register) >> 8); + return(READ_REGISTER_UCHAR (&NVRAM->NvramData)); +} + +static UCHAR +HalpReadClockRegister ( + UCHAR Register + ) + +/*++ + +Routine Description: + + This routine reads the specified realtime clock register. + change return value from BCD to binary integer. I think the chip + +Arguments: + + Register - Supplies the number of the register whose value is read. + +Return Value: + + The value of the register is returned as the function value. + +--*/ + +{ + UCHAR BcdValue; + + + BcdValue = HalpReadRawClockRegister(Register); + // + // If this is NOT the day-of-week register, then + // convert from BCD. If it is day-of-week, then + // mask off to 3-bits. + // + if (Register != TODC_DAY_OF_WEEK) + { + BcdValue = ((BcdValue >> 4) & 0xf) * 10 + (BcdValue & 0xf); + } + else + BcdValue &= 0x07; + + return BcdValue; +} + +static VOID +HalpWriteRawClockRegister ( + UCHAR Register, + UCHAR Value + ) + +/*++ + +Routine Description: + + This routine writes the specified value to the specified realtime + clock register. + +Arguments: + + Register - Supplies the number of the register whose value is written. + + Value - Supplies the value that is written to the specified register. + +Return Value: + + None + +--*/ + +{ + // + // Write the realtime clock register value. + // + WRITE_REGISTER_UCHAR (&NVRAM->NvramIndexLo, (RTC_BASE + Register) & 0xFF); + WRITE_REGISTER_UCHAR (&NVRAM->NvramIndexHi, (RTC_BASE + Register) >> 8); + WRITE_REGISTER_UCHAR (&NVRAM->NvramData, Value); +} + +static VOID +HalpWriteClockRegister ( + UCHAR Register, + UCHAR Value + ) + +/*++ + +Routine Description: + + This routine writes the specified value to the specified realtime + clock register. + + The value is first converted to BCD format before being written to + the clock register. + +Arguments: + + Register - Supplies the number of the register whose value is written. + + Value - Supplies the value that is written to the specified register. + +Return Value: + + None + +--*/ + +{ + UCHAR BcdValue; + + // + // First ensure that the value is in range 0 - 99 + // + BcdValue = (((Value % 100) / 10) << 4) | (Value % 10); + HalpWriteRawClockRegister(Register, BcdValue); +} diff --git a/private/ntos/nthals/haleagle/ppc/pcibios.c b/private/ntos/nthals/haleagle/ppc/pcibios.c new file mode 100644 index 000000000..a922c00e3 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pcibios.c @@ -0,0 +1,1056 @@ +/*++ + + +Copyright (C) 1996 Motorola Inc. + +Module Name: + + pcibios.c + +Abstract: + + Emulate PCI BIOS functions. + + Note that the HAL bus functions (HalGetBusData, etc.) are not + available at this phase of initialization, all of the work has + to be done here. + +Author: + + Scott Geranen + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#include "halp.h" +#include "pci.h" +#include "pcip.h" + +#include "pxmemctl.h" +#include "pxpcisup.h" + +#include "emulate.h" +#include "pcibios.h" + +UCHAR SBReadConfigByte( + IN UCHAR Bus, + IN UCHAR Device, + IN UCHAR Function, + IN UCHAR Register + ); + +USHORT SBReadConfigWord( + IN UCHAR Bus, + IN UCHAR Device, + IN UCHAR Function, + IN UCHAR Register + ); + +ULONG SBReadConfigDword( + IN UCHAR Bus, + IN UCHAR Device, + IN UCHAR Function, + IN UCHAR Register + ); + +VOID SBWriteConfigByte( + IN UCHAR Bus, + IN UCHAR Device, + IN UCHAR Function, + IN UCHAR Register, + IN UCHAR Data + ); + +VOID SBWriteConfigWord( + IN UCHAR Bus, + IN UCHAR Device, + IN UCHAR Function, + IN UCHAR Register, + IN USHORT Data + ); + +VOID SBWriteConfigDword( + IN UCHAR Bus, + IN UCHAR Device, + IN UCHAR Function, + IN UCHAR Register, + IN ULONG Data + ); + +// +// Last PCI bus in the system. +// +extern UCHAR HalpLastPciBus; + +// +// Mapped I/O space. +// +#define CONFIG_ADDR (&((PPLANAR_CONTROL)HalpIoControlBase)->ConfigAddress) +#define CONFIG_DATA (&((PPLANAR_CONTROL)HalpIoControlBase)->ConfigData) + + +BOOLEAN +HalpEmulatePciBios( + IN OUT PRXM_CONTEXT P + ) +/*++ + +Routine Description: + + This function emulates the PCI BIOS Specification, revision 2.1. The + specification is available from the PCI Special Interest Group. + + This function assumes that it is being called during phase 0 initialization. + The PCI bus functions are not available at this point, e.g. HalGetBusData. + +Arguments: + + P - Supplies a pointer to an emulator context structure. + +Return Value: + + TRUE (PCI BIOS was emulated) + +--*/ +{ +#if DBG + VOID TestPciBios(int flag); + + TestPciBios(0); +#endif + + switch (P->Gpr[EAX].Xl) { + + case PCIBIOS_PCI_BIOS_PRESENT: // Installation Check + + KdPrint(("PCI_BIOS_PRESENT\n")); + + P->Gpr[EDX].Exx = 0x20494350; // "PCI " + + P->Gpr[EAX].Xh = 0x00; // 00 == BIOS present + P->Gpr[EAX].Xl = 0x11; // PCI Hardware Characteristics (mech #1) + + P->Gpr[EBX].Xh = 0x02; // PCI Interface Level Major Version + P->Gpr[EBX].Xl = 0x10; // PCI Interface Level (BCD) + + P->Gpr[ECX].Xl = HalpLastPciBus; // Last PCI bus number + + P->Eflags.CF = 0; // reset == PCI BIOS present + + break; + + case PCIBIOS_FIND_PCI_DEVICE: + { + USHORT DevID = P->Gpr[ECX].Xx; + USHORT VenID = P->Gpr[EDX].Xx; + USHORT DevIndex = P->Gpr[ESI].Xx; + + UCHAR Bus, Device, Function, Header, NumFunctions; + BOOLEAN Found = FALSE; + + KdPrint(("Looking for instance %d of 0x%X, 0x%X\n", DevIndex, DevID, VenID)); + + if (VenID == 0xFFFF) { + + P->Gpr[EAX].Xh = PCIBIOS_BAD_VENDOR_ID; + P->Eflags.CF = 1; // set == error + + } else { + + for (Bus = 0; Bus <= HalpLastPciBus; Bus++) { + for (Device = 0; Device < PCI_MAX_DEVICES; Device++) { + + if (SBReadConfigWord(Bus, Device, 0, + FIELD_OFFSET(PCI_COMMON_CONFIG, VendorID)) == 0xFFFF) { + + continue; // no device here + + } + + Header = SBReadConfigByte( + Bus, Device, 0, + FIELD_OFFSET(PCI_COMMON_CONFIG, HeaderType)); + + NumFunctions = Header & PCI_MULTIFUNCTION ? 8 : 1; + + for (Function = 0; Function < NumFunctions; Function++) { + + if (SBReadConfigWord(Bus, Device, Function, + FIELD_OFFSET(PCI_COMMON_CONFIG, VendorID)) == VenID) { + + if (SBReadConfigWord(Bus, Device, Function, + FIELD_OFFSET(PCI_COMMON_CONFIG, DeviceID)) == DevID) { + + Found = (DevIndex == 0); + DevIndex--; + } + } + if (Found) break; // function + } + if (Found) break; // device + } + if (Found) break; // bus + } + + if (Found) { + + KdPrint(("Found at %d, %d, %d\n", Bus, Device, Function)); + + P->Gpr[EBX].Xh = Bus; + P->Gpr[EBX].Xl = (Device << 3) + Function; + P->Gpr[EAX].Xh = PCIBIOS_SUCCESSFUL; + + P->Eflags.CF = 0; // clear == success + + } else { + + KdPrint(("Not found\n")); + + P->Gpr[EAX].Xh = PCIBIOS_DEVICE_NOT_FOUND; + + P->Eflags.CF = 1; // set == error + } + + } + } + break; + + + case PCIBIOS_FIND_PCI_CLASS_CODE: + { + ULONG ClassCode = (P->Gpr[ECX].Exx) << 8; // see comments below + USHORT DevIndex = P->Gpr[ESI].Xx; + + UCHAR Bus, Device, Function, Header, NumFunctions; + BOOLEAN Found = FALSE; + + KdPrint(("Looking for class instance %d of 0x%X\n", DevIndex, P->Gpr[ECX].Exx)); + + for (Bus = 0; Bus <= HalpLastPciBus; Bus++) { + for (Device = 0; Device < PCI_MAX_DEVICES; Device++) { + + if (SBReadConfigWord(Bus, Device, 0, + FIELD_OFFSET(PCI_COMMON_CONFIG, VendorID)) == 0xFFFF) { + + continue; // no device here + + } + + Header = SBReadConfigByte( + Bus, Device, 0, + FIELD_OFFSET(PCI_COMMON_CONFIG, HeaderType)); + + NumFunctions = Header & PCI_MULTIFUNCTION ? 8 : 1; + + for (Function = 0; Function < NumFunctions; Function++) { + + // + // The class code bytes are in the same Dword as + // the revision id: + // + // Byte + // 3 2 1 0 + // +-------------------+--------+ + // | class code | Rev id | + // +-------------------+--------+ + // + // Read the Dword and mask off the revision id. + // The class code we are looking for has been + // shifted up already above. + // + if ((SBReadConfigDword(Bus, Device, Function, + FIELD_OFFSET(PCI_COMMON_CONFIG, RevisionID)) + & 0xFFFFFF00) == ClassCode) { + + Found = (DevIndex == 0); + DevIndex--; + } + if (Found) break; // function + } + if (Found) break; // device + } + if (Found) break; // bus + } + + if (Found) { + + KdPrint(("Found at %d, %d, %d\n", Bus, Device, Function)); + + P->Gpr[EBX].Xh = Bus; + P->Gpr[EBX].Xl = (Device << 3) + Function; + P->Gpr[EAX].Xh = PCIBIOS_SUCCESSFUL; + + P->Eflags.CF = 0; // clear == success + + } else { + + KdPrint(("Not found\n")); + + P->Gpr[EAX].Xh = PCIBIOS_DEVICE_NOT_FOUND; + + P->Eflags.CF = 1; // set == error + } + } + break; + + case PCIBIOS_READ_CONFIG_BYTE: + + KdPrint(("read byte %d, %d, %d, %d\n", + P->Gpr[EBX].Xh, // Bus + (P->Gpr[EBX].Xl >> 3), // Device + (P->Gpr[EBX].Xl & 0x07), // Function + P->Gpr[EDI].Xl)); // Register + + P->Gpr[EAX].Xh = PCIBIOS_SUCCESSFUL; + P->Eflags.CF = 0; // clear == success + + P->Gpr[ECX].Xl = SBReadConfigByte( + P->Gpr[EBX].Xh, // Bus + (UCHAR)(P->Gpr[EBX].Xl >> 3), // Device + (UCHAR)(P->Gpr[EBX].Xl & 0x07), // Function + P->Gpr[EDI].Xl); // Register + + KdPrint(("Data = 0x%X\n", P->Gpr[ECX].Xl)); + + break; + + case PCIBIOS_READ_CONFIG_WORD: + + KdPrint(("read word %d, %d, %d, %d\n", + P->Gpr[EBX].Xh, // Bus + (P->Gpr[EBX].Xl >> 3), // Device + (P->Gpr[EBX].Xl & 0x07), // Function + P->Gpr[EDI].Xl)); // Register + + if ((P->Gpr[EDI].Xl & 1) == 0) { + + P->Gpr[EAX].Xh = PCIBIOS_SUCCESSFUL; + P->Eflags.CF = 0; // clear == success + + P->Gpr[ECX].Xx = SBReadConfigWord( + P->Gpr[EBX].Xh, // Bus + (UCHAR)(P->Gpr[EBX].Xl >> 3), // Device + (UCHAR)(P->Gpr[EBX].Xl & 0x07), // Function + P->Gpr[EDI].Xl); // Register + } else { + + P->Gpr[EAX].Xh = PCIBIOS_BAD_REGISTER_NUMBER; + P->Eflags.CF = 1; // set == error + } + + KdPrint(("Data = 0x%X\n", P->Gpr[ECX].Xx)); + + break; + + case PCIBIOS_READ_CONFIG_DWORD: + + KdPrint(("read Dword %d, %d, %d, %d\n", + P->Gpr[EBX].Xh, // Bus + (P->Gpr[EBX].Xl >> 3), // Device + (P->Gpr[EBX].Xl & 0x07), // Function + P->Gpr[EDI].Xl)); // Register + + if ((P->Gpr[EDI].Xl & 3) == 0) { + P->Gpr[EAX].Xh = PCIBIOS_SUCCESSFUL; + P->Eflags.CF = 0; // clear == success + + P->Gpr[ECX].Exx = SBReadConfigDword( + P->Gpr[EBX].Xh, // Bus + (UCHAR)(P->Gpr[EBX].Xl >> 3), // Device + (UCHAR)(P->Gpr[EBX].Xl & 0x07), // Function + P->Gpr[EDI].Xl); // Register + } else { + + P->Gpr[EAX].Xh = PCIBIOS_BAD_REGISTER_NUMBER; + P->Eflags.CF = 1; // set == error + } + + KdPrint(("Data = 0x%X\n", P->Gpr[ECX].Exx)); + + break; + + case PCIBIOS_WRITE_CONFIG_BYTE: + + KdPrint(("Write byte 0x%X to %d, %d, %d, %d\n", + P->Gpr[ECX].Xl, // Value + P->Gpr[EBX].Xh, // Bus + (P->Gpr[EBX].Xl >> 3), // Device + (P->Gpr[EBX].Xl & 0x07), // Function + P->Gpr[EDI].Xl)); // Register + + P->Gpr[EAX].Xh = PCIBIOS_SUCCESSFUL; + P->Eflags.CF = 0; // clear == success + + SBWriteConfigByte( P->Gpr[EBX].Xh, // Bus + (UCHAR)(P->Gpr[EBX].Xl >> 3), // Device + (UCHAR)(P->Gpr[EBX].Xl & 0x07), // Function + P->Gpr[EDI].Xl, // Register + P->Gpr[ECX].Xl); // Value + break; + + case PCIBIOS_WRITE_CONFIG_WORD: + + KdPrint(("Write word 0x%X to %d, %d, %d, %d\n", + P->Gpr[ECX].Xx, // Value + P->Gpr[EBX].Xh, // Bus + (P->Gpr[EBX].Xl >> 3), // Device + (P->Gpr[EBX].Xl & 0x07), // Function + P->Gpr[EDI].Xl)); // Register + + if ((P->Gpr[EDI].Xl & 1) == 0) { + P->Gpr[EAX].Xh = PCIBIOS_SUCCESSFUL; + P->Eflags.CF = 0; // clear == success + + SBWriteConfigWord( P->Gpr[EBX].Xh, // Bus + (UCHAR)(P->Gpr[EBX].Xl >> 3), // Device + (UCHAR)(P->Gpr[EBX].Xl & 0x07), // Function + P->Gpr[EDI].Xl, // Register + P->Gpr[ECX].Xx); // Value + } else { + + P->Gpr[EAX].Xh = PCIBIOS_BAD_REGISTER_NUMBER; + P->Eflags.CF = 1; // set == error + } + + break; + + case PCIBIOS_WRITE_CONFIG_DWORD: + + KdPrint(("Write Dword 0x%X to %d, %d, %d, %d\n", + P->Gpr[ECX].Exx, // Value + P->Gpr[EBX].Xh, // Bus + (P->Gpr[EBX].Xl >> 3), // Device + (P->Gpr[EBX].Xl & 0x07), // Function + P->Gpr[EDI].Xl)); // Register + + if ((P->Gpr[EDI].Xl & 3) == 0) { + P->Gpr[EAX].Xh = PCIBIOS_SUCCESSFUL; + P->Eflags.CF = 0; // clear == success + + SBWriteConfigDword( P->Gpr[EBX].Xh, // Bus + (UCHAR)(P->Gpr[EBX].Xl >> 3), // Device + (UCHAR)(P->Gpr[EBX].Xl & 0x07), // Function + P->Gpr[EDI].Xl, // Register + P->Gpr[ECX].Exx); // Value + } else { + + P->Gpr[EAX].Xh = PCIBIOS_BAD_REGISTER_NUMBER; + P->Eflags.CF = 1; // set == error + } + + break; + + case PCIBIOS_GENERATE_SPECIAL_CYCLE: + { + PCI_TYPE1_CFG_BITS Addr; + + KdPrint(("Generate Special cycle %d, 0x%X\n", + P->Gpr[EBX].Xh, // Bus + P->Gpr[ECX].Exx)); // Value + + Addr.u.AsULONG = 0; // initialize reserved bits + + Addr.u.bits.Enable = TRUE; + + Addr.u.bits.BusNumber = P->Gpr[EBX].Xh; + Addr.u.bits.DeviceNumber = 0x1f; + Addr.u.bits.FunctionNumber = 7; + + WRITE_PORT_ULONG (CONFIG_ADDR, Addr.u.AsULONG ); + + WRITE_PORT_ULONG (CONFIG_DATA, P->Gpr[EDX].Exx); + + P->Gpr[EAX].Xh = PCIBIOS_SUCCESSFUL; + P->Eflags.CF = 0; // clear == success + } + + break; + + + case PCIBIOS_GET_IRQ_ROUTING_OPTIONS: // not supported + case PCIBIOS_SET_IRQ_ROUTING_OPTIONS: // not supported + default: + + KdPrint(("PCI BIOS: function %x not supported\n", P->Gpr[EAX].Xl)); + + P->Gpr[EAX].Xh = PCIBIOS_FUNC_NOT_SUPPORTED; + + P->Eflags.CF = 1; // set == error + + break; + } + + return TRUE; +} + +UCHAR +SBReadConfigByte( + IN UCHAR Bus, + IN UCHAR Device, + IN UCHAR Function, + IN UCHAR Register + ) +{ + ULONG ByteInRegister; + PCI_TYPE1_CFG_BITS Addr; + + Addr.u.AsULONG = 0; // initialize reserved bits + + Addr.u.bits.Enable = TRUE; + + Addr.u.bits.BusNumber = Bus; + Addr.u.bits.DeviceNumber = Device; + Addr.u.bits.FunctionNumber = Function; + + ByteInRegister = Register % sizeof(ULONG); + Addr.u.bits.RegisterNumber = Register / sizeof(ULONG); + + WRITE_PORT_ULONG (CONFIG_ADDR, Addr.u.AsULONG ); + + return READ_PORT_UCHAR ((PUCHAR)CONFIG_DATA + ByteInRegister); +} + +USHORT +SBReadConfigWord( + IN UCHAR Bus, + IN UCHAR Device, + IN UCHAR Function, + IN UCHAR Register + ) +{ + ULONG WordInRegister; + PCI_TYPE1_CFG_BITS Addr; + + Addr.u.AsULONG = 0; // initialize reserved bits + + Addr.u.bits.Enable = TRUE; + + Addr.u.bits.BusNumber = Bus; + Addr.u.bits.DeviceNumber = Device; + Addr.u.bits.FunctionNumber = Function; + + WordInRegister = Register % sizeof(ULONG); + Addr.u.bits.RegisterNumber = Register / sizeof(ULONG); + + WRITE_PORT_ULONG (CONFIG_ADDR, Addr.u.AsULONG ); + + return READ_PORT_USHORT ((PUCHAR)CONFIG_DATA + WordInRegister); +} + +ULONG +SBReadConfigDword( + IN UCHAR Bus, + IN UCHAR Device, + IN UCHAR Function, + IN UCHAR Register + ) +{ + PCI_TYPE1_CFG_BITS Addr; + + Addr.u.AsULONG = 0; // initialize reserved bits + + Addr.u.bits.Enable = TRUE; + + Addr.u.bits.BusNumber = Bus; + Addr.u.bits.DeviceNumber = Device; + Addr.u.bits.FunctionNumber = Function; + + Addr.u.bits.RegisterNumber = Register / sizeof(ULONG); + + WRITE_PORT_ULONG (CONFIG_ADDR, Addr.u.AsULONG ); + + return READ_PORT_ULONG (CONFIG_DATA); +} + +VOID +SBWriteConfigByte( + IN UCHAR Bus, + IN UCHAR Device, + IN UCHAR Function, + IN UCHAR Register, + IN UCHAR Data + ) +{ + ULONG ByteInRegister; + PCI_TYPE1_CFG_BITS Addr; + + Addr.u.AsULONG = 0; // initialize reserved bits + + Addr.u.bits.Enable = TRUE; + + Addr.u.bits.BusNumber = Bus; + Addr.u.bits.DeviceNumber = Device; + Addr.u.bits.FunctionNumber = Function; + + ByteInRegister = Register % sizeof(ULONG); + Addr.u.bits.RegisterNumber = Register / sizeof(ULONG); + + WRITE_PORT_ULONG (CONFIG_ADDR, Addr.u.AsULONG ); + + WRITE_PORT_UCHAR ((PUCHAR)CONFIG_DATA + ByteInRegister, Data); +} + +VOID +SBWriteConfigWord( + IN UCHAR Bus, + IN UCHAR Device, + IN UCHAR Function, + IN UCHAR Register, + IN USHORT Data + ) +{ + ULONG WordInRegister; + PCI_TYPE1_CFG_BITS Addr; + + Addr.u.AsULONG = 0; // initialize reserved bits + + Addr.u.bits.Enable = TRUE; + + Addr.u.bits.BusNumber = Bus; + Addr.u.bits.DeviceNumber = Device; + Addr.u.bits.FunctionNumber = Function; + + WordInRegister = Register % sizeof(ULONG); + Addr.u.bits.RegisterNumber = Register / sizeof(ULONG); + + WRITE_PORT_ULONG (CONFIG_ADDR, Addr.u.AsULONG ); + + WRITE_PORT_USHORT ((PUCHAR)CONFIG_DATA + WordInRegister, Data); +} + +VOID +SBWriteConfigDword( + IN UCHAR Bus, + IN UCHAR Device, + IN UCHAR Function, + IN UCHAR Register, + IN ULONG Data + ) +{ + PCI_TYPE1_CFG_BITS Addr; + + Addr.u.AsULONG = 0; // initialize reserved bits + + Addr.u.bits.Enable = TRUE; + + Addr.u.bits.BusNumber = Bus; + Addr.u.bits.DeviceNumber = Device; + Addr.u.bits.FunctionNumber = Function; + + Addr.u.bits.RegisterNumber = Register / sizeof(ULONG); + + WRITE_PORT_ULONG (CONFIG_ADDR, Addr.u.AsULONG ); + + WRITE_PORT_ULONG (CONFIG_DATA, Data); +} + + +#if DBG + +// Modify this code to match your particular HW configuration +// +// Use the debugger to force flag to 1. + +VOID +initregs(PRXM_CONTEXT P) +{ + P->Gpr[EAX].Exx = 0x1234B100; + P->Gpr[EBX].Exx = 0x23456789; + P->Gpr[ECX].Exx = 0x3456789A; + P->Gpr[EDX].Exx = 0x456789AB; + P->Gpr[ESP].Exx = 0x87654321; + P->Gpr[EBP].Exx = 0x98765432; + P->Gpr[ESI].Exx = 0xA9876543; + P->Gpr[EDI].Exx = 0xBA987654; + + P->Eflags.CF = 1; +} + +VOID +dumpregs(PRXM_CONTEXT P) +{ + DbgPrint("Carry = %d\n", P->Eflags.CF); + + DbgPrint("EAX = %X, EBX = %X, ECX = %X, EDX = %X\n", + P->Gpr[EAX], P->Gpr[EBX], P->Gpr[ECX], P->Gpr[EDX]); + + DbgPrint("ESP = %X, EBP = %X, ESI = %X, EDI = %X\n", + P->Gpr[ESP], P->Gpr[EBP], P->Gpr[ESI], P->Gpr[EDI]); +} + + +VOID +TestPciBios(int flag) +{ +int i; +XM_CONTEXT Context; +PRXM_CONTEXT P = &Context; + + if (flag == 0) return; + + DbgBreakPoint(); + initregs(P); + dumpregs(P); + DbgBreakPoint(); + + P->Gpr[EAX].Xl = 1; // bios present + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 2; // find device + P->Gpr[ECX].Xx = 0xffff; + P->Gpr[EDX].Xx = 0xffff; + P->Gpr[ESI].Xx = 0; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + for (P->Eflags.CF = 0, i = 0; P->Eflags.CF == 0; i++) + { + initregs(P); + P->Gpr[EAX].Xl = 2; // find device + P->Gpr[ECX].Xx = 0x0453; + P->Gpr[EDX].Xx = 0x8086; + P->Gpr[ESI].Xx = i; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + } + + for (P->Eflags.CF = 0, i = 0; P->Eflags.CF == 0; i++) + { + initregs(P); + P->Gpr[EAX].Xl = 2; // find device + P->Gpr[ECX].Xx = 0x0002; + P->Gpr[EDX].Xx = 0x1011; // DEC ethernet + P->Gpr[ESI].Xx = i; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + } + + for (P->Eflags.CF = 0, i = 0; P->Eflags.CF == 0; i++) + { + initregs(P); + P->Gpr[EAX].Xl = 2; // find device + P->Gpr[ECX].Xx = 0x7278; + P->Gpr[EDX].Xx = 0x9004; // adaptec + P->Gpr[ESI].Xx = i; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + } + + + initregs(P); + P->Gpr[EAX].Xl = 2; // find device + P->Gpr[ECX].Xx = 0x1234; + P->Gpr[EDX].Xx = 0x5678; + P->Gpr[ESI].Xx = 0; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + for (P->Eflags.CF = 0, i = 0; P->Eflags.CF == 0; i++) + { + initregs(P); + P->Gpr[EAX].Xl = 3; // find class code + P->Gpr[ECX].Exx = 0x030000; // vga + P->Gpr[ESI].Xx = i; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + } + + for (P->Eflags.CF = 0, i = 0; P->Eflags.CF == 0; i++) + { + initregs(P); + P->Gpr[EAX].Xl = 3; // find class code + P->Gpr[ECX].Exx = 0x020000; // ethernet + P->Gpr[ESI].Xx = i; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + } + + for (P->Eflags.CF = 0, i = 0; P->Eflags.CF == 0; i++) + { + initregs(P); + P->Gpr[EAX].Xl = 3; // find class code + P->Gpr[ECX].Exx = 0x010000; // scsi + P->Gpr[ESI].Xx = i; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + } + + initregs(P); + P->Gpr[EAX].Xl = 3; // find class code + P->Gpr[ECX].Exx = 0xABCDEF; // not found + P->Gpr[ESI].Xx = 0; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + + initregs(P); + P->Gpr[EAX].Xl = 6; // generate special cycle + P->Gpr[EBX].Xh = 0; + P->Gpr[EDX].Exx = 0x00000002; // x86 specific + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 0xE; // get irq routing + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 0xF; // set irq routing + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 8; // read byte + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (2 << 3) + 0; // non-existent + P->Gpr[EDI].Xx = 1; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 8; // read byte + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (17 << 3) + 0; + P->Gpr[EDI].Xx = 1; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + + initregs(P); + P->Gpr[EAX].Xl = 8; // read byte + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (17 << 3) + 1; // non-existent function + P->Gpr[EDI].Xx = 1; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 8; // read byte + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (17 << 3) + 4; // existent function + P->Gpr[EDI].Xx = 1; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + + initregs(P); + P->Gpr[EAX].Xl = 9; // read word + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (17 << 3) + 0; + P->Gpr[EDI].Xx = 1; // bad register number + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 9; // read word + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (2 << 3) + 0; // non-existent + P->Gpr[EDI].Xx = 2; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 9; // read word + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (17 << 3) + 0; + P->Gpr[EDI].Xx = 2; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 9; // read word + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (17 << 3) + 1; // non-existent function + P->Gpr[EDI].Xx = 2; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 9; // read word + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (17 << 3) + 4; // existent function + P->Gpr[EDI].Xx = 2; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 0xA; // read Dword + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (17 << 3) + 0; + P->Gpr[EDI].Xx = 2; // bad register number + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 0xA; // read Dword + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (2 << 3) + 0; // non-existent + P->Gpr[EDI].Xx = 4; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 0xA; // read Dword + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (17 << 3) + 0; + P->Gpr[EDI].Xx = 4; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 0xA; // read Dword + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (17 << 3) + 1; // non-existent function + P->Gpr[EDI].Xx = 4; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 0xA; // read Dword + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (17 << 3) + 4; // existent function + P->Gpr[EDI].Xx = 4; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 0xA; // read Dword + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (17 << 3) + 0; + P->Gpr[EDI].Xx = 2; // bad register number + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 0xA; // read Dword + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (16 << 3) + 0; + P->Gpr[EDI].Xx = 0x3C; + HalpEmulatePciBios(P); + dumpregs(P); + initregs(P); + P->Gpr[EAX].Xl = 0xB; // write byte + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (16 << 3) + 0; + P->Gpr[EDI].Xx = 0x3C; + P->Gpr[ECX].Xl = 0xAB; + HalpEmulatePciBios(P); + dumpregs(P); + initregs(P); + P->Gpr[EAX].Xl = 0xA; // read Dword + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (16 << 3) + 0; + P->Gpr[EDI].Xx = 0x3C; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 0xC; // write word + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (16 << 3) + 0; + P->Gpr[EDI].Xx = 0x3F; // bad register + P->Gpr[ECX].Xl = 0xAB; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 0xA; // read Dword + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (16 << 3) + 0; + P->Gpr[EDI].Xx = 0x30; + HalpEmulatePciBios(P); + dumpregs(P); + initregs(P); + P->Gpr[EAX].Xl = 0xC; // write word + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (16 << 3) + 0; + P->Gpr[EDI].Xx = 0x30; + P->Gpr[ECX].Xx = 0xFFFF; + HalpEmulatePciBios(P); + dumpregs(P); + initregs(P); + P->Gpr[EAX].Xl = 0xA; // read Dword + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (16 << 3) + 0; + P->Gpr[EDI].Xx = 0x30; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 0xD; // write Dword + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (16 << 3) + 0; + P->Gpr[EDI].Xx = 0x3F; // bad register + P->Gpr[ECX].Xl = 0xAB; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 0xA; // read Dword + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (16 << 3) + 0; + P->Gpr[EDI].Xx = 0x30; + HalpEmulatePciBios(P); + dumpregs(P); + initregs(P); + P->Gpr[EAX].Xl = 0xD; // write word + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (16 << 3) + 0; + P->Gpr[EDI].Xx = 0x30; + P->Gpr[ECX].Exx = 0xFFFFFFFF; + HalpEmulatePciBios(P); + dumpregs(P); + initregs(P); + P->Gpr[EAX].Xl = 0xA; // read Dword + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (16 << 3) + 0; + P->Gpr[EDI].Xx = 0x30; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + DbgPrint("All done!\n"); + DbgBreakPoint(); +} +#endif diff --git a/private/ntos/nthals/haleagle/ppc/pcibios.h b/private/ntos/nthals/haleagle/ppc/pcibios.h new file mode 100644 index 000000000..2e47f6b23 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pcibios.h @@ -0,0 +1,58 @@ +/*++ BUILD Version: 0000 // Increment this if a change has global effects + +Copyright (c) 1996 Motorola Inc. + +Module Name: + + pcibios.h + +Abstract: + + This module contains the private header file for the PCI bios + emulation. + +Author: + + Scott Geranen (3-4-96) + +Revision History: + +--*/ + +#ifndef _PCIBIOS_ +#define _PCIBIOS_ + + +BOOLEAN HalpEmulatePciBios( + IN OUT PRXM_CONTEXT P + ); + +// +// PCI BIOS v2.1 functions +// +#define PCIBIOS_PCI_FUNCTION_ID 0xB1 +#define PCIBIOS_PCI_BIOS_PRESENT 0x01 +#define PCIBIOS_FIND_PCI_DEVICE 0x02 +#define PCIBIOS_FIND_PCI_CLASS_CODE 0x03 +#define PCIBIOS_GENERATE_SPECIAL_CYCLE 0x06 +#define PCIBIOS_READ_CONFIG_BYTE 0x08 +#define PCIBIOS_READ_CONFIG_WORD 0x09 +#define PCIBIOS_READ_CONFIG_DWORD 0x0A +#define PCIBIOS_WRITE_CONFIG_BYTE 0x0B +#define PCIBIOS_WRITE_CONFIG_WORD 0x0C +#define PCIBIOS_WRITE_CONFIG_DWORD 0x0D +#define PCIBIOS_GET_IRQ_ROUTING_OPTIONS 0x0E +#define PCIBIOS_SET_IRQ_ROUTING_OPTIONS 0x0F + +// +// PCI BIOS v2.1 status codes: +// +#define PCIBIOS_SUCCESSFUL 0x00 +#define PCIBIOS_FUNC_NOT_SUPPORTED 0x81 +#define PCIBIOS_BAD_VENDOR_ID 0x83 +#define PCIBIOS_DEVICE_NOT_FOUND 0x86 +#define PCIBIOS_BAD_REGISTER_NUMBER 0x87 +#define PCIBIOS_SET_FAILED 0x88 +#define PCIBIOS_BUFFER_TOO_SMALL 0x89 + +#endif // _PCIBIOS_ diff --git a/private/ntos/nthals/haleagle/ppc/pcip.h b/private/ntos/nthals/haleagle/ppc/pcip.h new file mode 100644 index 000000000..3aa4853ca --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pcip.h @@ -0,0 +1,186 @@ +// +// Hal specific PCI bus structures +// + +typedef NTSTATUS +(*PciIrqRange) ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER PciSlot, + OUT PSUPPORTED_RANGE *Interrupt + ); + +typedef struct tagPCIPBUSDATA { + + // + // Defined PCI data + // + + PCIBUSDATA CommonData; + + // + // Implementation specific data + // + + union { + struct { + PULONG Address; + ULONG Data; + } Type1; + struct { + PUCHAR CSE; + PUCHAR Forward; + ULONG Base; + } Type2; + } Config; + + ULONG MaxDevice; + PciIrqRange GetIrqRange; + + BOOLEAN BridgeConfigRead; + UCHAR ParentBus; + UCHAR reserved[2]; + UCHAR SwizzleIn[4]; + + RTL_BITMAP DeviceConfigured; + ULONG ConfiguredBits[PCI_MAX_DEVICES * PCI_MAX_FUNCTION / 32]; +} PCIPBUSDATA, *PPCIPBUSDATA; + +#define PciBitIndex(Dev,Fnc) (Fnc*32 + Dev); + +#define PCI_CONFIG_TYPE(PciData) ((PciData)->HeaderType & ~PCI_MULTIFUNCTION) + +#define Is64BitBaseAddress(a) \ + (((a & PCI_ADDRESS_IO_SPACE) == 0) && \ + ((a & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT)) + + +#if DBG +#define IRQXOR 0x2B +#else +#define IRQXOR 0 +#endif + + +// +// Prototypes for functions in ixpcibus.c +// + +VOID +HalpInitializePciBus ( + VOID + ); + +VOID +HalpReadPCIConfig ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ); + + +VOID +HalpWritePCIConfig ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +PBUS_HANDLER +HalpAllocateAndInitPciBusHandler ( + IN ULONG HwType, + IN ULONG BusNo, + IN BOOLEAN TestAllocation + ); + + +// +// Prototypes for functions in ixpciint.c +// + +ULONG +HalpGetPCIIntOnISABus ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ); + +VOID +HalpPCIAcquireType2Lock ( + PKSPIN_LOCK SpinLock, + PKIRQL Irql + ); + +VOID +HalpPCIReleaseType2Lock ( + PKSPIN_LOCK SpinLock, + KIRQL Irql + ); + +NTSTATUS +HalpAdjustPCIResourceList ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList + ); + +VOID +HalpPCIPin2ISALine ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER SlotNumber, + IN PPCI_COMMON_CONFIG PciData + ); + +VOID +HalpPCIISALine2Pin ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER SlotNumber, + IN PPCI_COMMON_CONFIG PciNewData, + IN PPCI_COMMON_CONFIG PciOldData + ); + +NTSTATUS +HalpGetISAFixedPCIIrq ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER PciSlot, + OUT PSUPPORTED_RANGE *Interrupt + ); + +// +// Prototypes for functions in ixpcibrd.c +// + +BOOLEAN +HalpGetPciBridgeConfig ( + IN ULONG HwType, + IN PUCHAR MaxPciBus + ); + +VOID +HalpFixupPciSupportedRanges ( + IN ULONG MaxBuses + ); + +// +// +// + +#ifdef SUBCLASSPCI + +VOID +HalpSubclassPCISupport ( + IN PBUS_HANDLER BusHandler, + IN ULONG HwType + ); + +#endif diff --git a/private/ntos/nthals/haleagle/ppc/prepnvr.h b/private/ntos/nthals/haleagle/ppc/prepnvr.h new file mode 100644 index 000000000..93c8c09bc --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/prepnvr.h @@ -0,0 +1,134 @@ +/* Structure map for NVRAM on PowerPC Reference Platform */ + +/* Revision 1 changes (8/25/94): + - Power Management (RESTART_BLOCK struct) + - Normal added to PM_MODE + - OSIRQMask (HEADER struct) */ + +/* All fields are either character/byte strings which are valid either +endian or they are big-endian numbers. + +There are a number of Date and Time fields which are in RTC format, +big-endian. These are stored in UT (GMT). + +For enum's: if given in hex then they are bit significant, i.e. only +one bit is on for each enum. +*/ + +#ifndef _NVRAM_ +#define _NVRAM_ + +#define NVSIZE 4096 /* size of NVRAM */ +#define OSAREASIZE 512 /* size of OSArea space */ +#define CONFSIZE 1024 /* guess at size of Configuration space */ + +typedef struct _SECURITY { + unsigned long BootErrCnt; /* Count of boot password errors */ + unsigned long ConfigErrCnt; /* Count of config password errors */ + unsigned long BootErrorDT[2]; /* Date&Time from RTC of last error in pw */ + unsigned long ConfigErrorDT[2]; /* Date&Time from RTC of last error in pw */ + unsigned long BootCorrectDT[2]; /* Date&Time from RTC of last correct pw */ + unsigned long ConfigCorrectDT[2]; /* Date&Time from RTC of last correct pw */ + unsigned long BootSetDT[2]; /* Date&Time from RTC of last set of pw */ + unsigned long ConfigSetDT[2]; /* Date&Time from RTC of last set of pw */ + unsigned char Serial[16]; /* Box serial number */ + } SECURITY; + +typedef enum _OS_ID { + Unknown = 0, + Firmware = 1, + AIX = 2, + NT = 3, + WPOS2 = 4, + WPAIX = 5, + Taligent = 6, + Solaris = 7, + Netware = 8, + USL = 9, + Low_End_Client = 10, + SCO = 11 + } OS_ID; + +typedef struct _ERROR_LOG { + unsigned char ErrorLogEntry[40]; /* To be architected */ + } ERROR_LOG; + +/*---Revision 1: Change the following struct:---*/ +typedef struct _RESUME_BLOCK { + /* Hibernation Resume Device will be an + environment variable */ + unsigned long CheckSum; /* Checksum of RESUME_BLOCK */ + volatile unsigned long BootStatus; + + void * ResumeAddr; /* For Suspend Resume */ + void * SaveAreaAddr; /* For Suspend Resume */ + unsigned long SaveAreaLength; /* For Suspend Resume */ + + unsigned long HibResumeImageRBA; /* RBA (512B blocks) of compressed OS + memory image to be loaded by FW + on Resume from hibernation */ + unsigned long HibResumeImageRBACount; /* Size of image in 512B blocks*/ + unsigned long Reserved; + } RESUME_BLOCK; + +typedef enum _OSAREA_USAGE { + Empty = 0, + Used = 1 + } OSAREA_USAGE; + +typedef enum _PM_MODE { + Suspend = 0x80, /* Part of state is in memory */ + Hibernate = 0x40, /* Nothing in memory - state saved elsewhere */ +/* Revision 1: Normal added (actually was already here) */ + Normal = 0x00 /* No power management in effect */ + } PMMode; + +typedef struct _HEADER { + unsigned short Size; /* NVRAM size in K(1024) */ + unsigned char Version; /* Structure map different */ + unsigned char Revision; /* Structure map the same - + may be new values in old fields + in other words old code still works */ + unsigned short Crc1; /* check sum from beginning of nvram to OSArea */ + unsigned short Crc2; /* check sum of config */ + unsigned char LastOS; /* OS_ID */ + unsigned char Endian; /* B if big endian, L if little endian */ + unsigned char OSAreaUsage; /* OSAREA_USAGE */ + unsigned char PMMode; /* Shutdown mode */ + RESUME_BLOCK ResumeBlock; + SECURITY Security; + ERROR_LOG ErrorLog[2]; + +/* Global Environment information */ + void * GEAddress; + unsigned long GELength; + /* Date&Time from RTC of last change to Global Environment */ + unsigned long GELastWriteDT[2]; + +/* Configuration information */ + void * ConfigAddress; + unsigned long ConfigLength; + /* Date&Time from RTC of last change to Configuration */ + unsigned long ConfigLastWriteDT[2]; + unsigned long ConfigCount; /* Count of entries in Configuration */ + +/* OS dependent temp area */ + void * OSAreaAddress; + unsigned long OSAreaLength; + /* Date&Time from RTC of last change to OSAreaArea */ + unsigned long OSAreaLastWriteDT[2]; + +/* Revision 1: add this mask - function tbd */ + /*unsigned short OSIRQMask; OS to FW IRQ Mask - "I've used this one" */ + } HEADER; + + +/* Here is the whole map of the NVRAM */ +typedef struct _NVRAM_MAP { + HEADER Header; + unsigned char GEArea[NVSIZE-CONFSIZE-OSAREASIZE-sizeof(HEADER)]; + unsigned char OSArea[OSAREASIZE]; + unsigned char ConfigArea[CONFSIZE]; + } NVRAM_MAP; + +#endif /* ndef _NVRAM_ */ diff --git a/private/ntos/nthals/haleagle/ppc/pxbeep.c b/private/ntos/nthals/haleagle/ppc/pxbeep.c new file mode 100644 index 000000000..2ac4b543c --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxbeep.c @@ -0,0 +1,134 @@ +/*++ + +Copyright (c) 1991-1993 Microsoft Corporation + +Module Name: + + pxbeep.c + +Abstract: + + This module implements the HAL speaker "beep" routines for a Power PC + 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 = HalpIoControlBase; + TIMER_CONTROL timerControl; + ULONG newCount; + BOOLEAN Result; + + // + // Raise IRQL to dispatch level and acquire the beep spin lock. + // + + KeAcquireSpinLock(&HalpBeepLock, &OldIrql); + + // + // Stop the speaker. + // + + *((PUCHAR)&NmiStatus) = READ_REGISTER_UCHAR(&controlBase->NmiStatus); + NmiStatus.SpeakerGate = 0; + NmiStatus.SpeakerData = 0; + WRITE_REGISTER_UCHAR(&controlBase->NmiStatus, *((PUCHAR)&NmiStatus)); + + // + // If the specified frequency is zero, then the speaker is to be stopped. + // + + if (Frequency == 0) { + Result = TRUE; + + } else { + + // + // If the new count has a magnitude less than 65,536 (0x10000), then + // set the speaker time to the correct mode. Otherwise, return a value + // of FALSE sinc ethe frequency is out of range. + // + + newCount = TIMER_CLOCK_IN / Frequency; + if (newCount >= 0x10000) { + Result = FALSE; + + } else { + + // + // Set the speaker timer to the correct mode. + // + + timerControl.BcdMode = 0; + timerControl.Mode = TM_SQUARE_WAVE; + timerControl.SelectByte = SB_LSB_THEN_MSB; + timerControl.SelectCounter = SELECT_COUNTER_2; + WRITE_REGISTER_UCHAR(&controlBase->CommandMode1, *((PUCHAR) &timerControl)); + + // + // Set the speaker timer to the correct mode. + // + + WRITE_REGISTER_UCHAR(&controlBase->SpeakerTone, (UCHAR)(newCount & 0xff)); + WRITE_REGISTER_UCHAR(&controlBase->SpeakerTone, (UCHAR)(newCount >> 8)); + + // + // Start the speaker. + // + + NmiStatus.SpeakerGate = 1; + NmiStatus.SpeakerData = 1; + WRITE_REGISTER_UCHAR(&controlBase->NmiStatus, *((PUCHAR) &NmiStatus)); + Result = TRUE; + } + } + + // + // Release the beep spin lock and lower IRQL to its previous value. + // + + KeReleaseSpinLock(&HalpBeepLock, OldIrql); + return Result; +} diff --git a/private/ntos/nthals/haleagle/ppc/pxbusdat.c b/private/ntos/nthals/haleagle/ppc/pxbusdat.c new file mode 100644 index 000000000..ef7f3462b --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxbusdat.c @@ -0,0 +1,210 @@ +/*++ + + +Copyright (C) 1989-1995 Microsoft Corporation + +Module Name: + + pxbusdat.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: + + Ken Reneris (kenr) July-28-1994 + +Environment: + + Kernel mode + +Revision History: + + Jim Wooldridge Ported to PowerPC + + +--*/ + +#include "halp.h" + + +VOID HalpInitOtherBuses (VOID); + + +ULONG +HalpNoBusData ( + IN PVOID BusHandler, + IN PVOID RootHandler, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ); + + + + +// +// Prototype for system bus handlers +// + + +NTSTATUS +HalpAdjustIsaResourceList ( + IN PVOID BusHandler, + IN PVOID RootHandler, + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList + ); + +ULONG +HalpGetSystemInterruptVector ( + IN PVOID BusHandler, + IN PVOID RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ); + +ULONG +HalpGetIsaInterruptVector ( + IN PVOID BusHandler, + IN PVOID RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ); + +BOOLEAN +HalpTranslateSystemBusAddress ( + IN PVOID BusHandler, + IN PVOID RootHandler, + IN PHYSICAL_ADDRESS BusAddress, + IN OUT PULONG AddressSpace, + OUT PPHYSICAL_ADDRESS TranslatedAddress + ); + +VOID +HalpRegisterInternalBusHandlers ( + VOID + ); + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT,HalpRegisterInternalBusHandlers) +#pragma alloc_text(INIT,HalpAllocateBusHandler) +#endif + + +VOID +HalpRegisterInternalBusHandlers ( + VOID + ) +{ + PBUS_HANDLER Bus; + + if (KeGetCurrentPrcb()->Number) { + // only need to do this once + return ; + } + + // + // Initalize BusHandler data before registering any handlers + // + + HalpInitBusHandler (); + + // + // Build internal-bus 0, or system level bus + // + + Bus = HalpAllocateBusHandler ( + Internal, + ConfigurationSpaceUndefined, + 0, // Internal BusNumber 0 + InterfaceTypeUndefined, // no parent bus + 0, + 0 // no bus specfic data + ); + + Bus->GetInterruptVector = HalpGetSystemInterruptVector; + Bus->TranslateBusAddress = HalpTranslateSystemBusAddress; + + // + // Build Isa bus 0 + // + + Bus = HalpAllocateBusHandler (Isa, -1, 0, Internal, 0, 0); + Bus->GetBusData = HalpNoBusData; + Bus->GetInterruptVector = HalpGetIsaInterruptVector; + Bus->AdjustResourceList = HalpAdjustIsaResourceList; + + + HalpInitOtherBuses (); +} + + + +PBUS_HANDLER +HalpAllocateBusHandler ( + IN INTERFACE_TYPE InterfaceType, + IN BUS_DATA_TYPE BusDataType, + IN ULONG BusNumber, + IN INTERFACE_TYPE ParentBusInterfaceType, + IN ULONG ParentBusNumber, + IN ULONG BusSpecificData + ) +/*++ + +Routine Description: + + Stub function to map old style code into new HalRegisterBusHandler code. + + Note we can add our specific bus handler functions after this bus + handler structure has been added since this is being done during + hal initialization. + +--*/ +{ + PBUS_HANDLER Bus; + + + // + // Create bus handler - new style + // + + HaliRegisterBusHandler ( + InterfaceType, + BusDataType, + BusNumber, + ParentBusInterfaceType, + ParentBusNumber, + BusSpecificData, + NULL, + &Bus + ); + + if (InterfaceType != InterfaceTypeUndefined) { + Bus->BusAddresses = ExAllocatePool (SPRANGEPOOL, sizeof (SUPPORTED_RANGES)); + RtlZeroMemory (Bus->BusAddresses, sizeof (SUPPORTED_RANGES)); + Bus->BusAddresses->Version = BUS_SUPPORTED_RANGE_VERSION; + Bus->BusAddresses->Dma.Limit = 7; + Bus->BusAddresses->Memory.Limit = 0x3EFFFFFF; + Bus->BusAddresses->Memory.SystemAddressSpace = 0; + Bus->BusAddresses->Memory.SystemBase = PCI_MEMORY_PHYSICAL_BASE; + Bus->BusAddresses->IO.SystemBase = 0x80000000; + Bus->BusAddresses->IO.Limit = 0x3F7FFFFF; + Bus->BusAddresses->IO.SystemAddressSpace = 0; + Bus->BusAddresses->PrefetchMemory.Base = 1; + } + + + return Bus; +} + + + diff --git a/private/ntos/nthals/haleagle/ppc/pxcache.s b/private/ntos/nthals/haleagle/ppc/pxcache.s new file mode 100644 index 000000000..a8c393646 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxcache.s @@ -0,0 +1,208 @@ +//++ +// +// Copyright (c) 1993 IBM Corporation +// +// Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +// contains copyrighted material. Use of this file is restricted +// by the provisions of a Motorola Software License Agreement. +// +// Module Name: +// +// pxcache.s +// +// Abstract: +// +// This module implements the routines to flush cache on the PowerPC. +// +// Author: +// +// Peter L. Johnston (plj@vnet.ibm.com) September 1993 +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// 27-Dec-93 plj Added 603 support. +// 13-Mar-94 plj Fixed problem introduced during switch to PAS; +// added 604 support. +// 07-Oct-94 saj Check for length=0 in Range functions +//-- + +#include "kxppc.h" +#include "halppc.h" + + .extern HalpIoControlBase + +// NOTE: The 603's "I-Cache Flash Invalidate" and the 604's +// "I-Cache Invalidate All" basically perform the same function +// although the usage is slightly different. In the 603 case, +// ICFI must be cleared under program control after it is set. +// In the 604 the bit clears automatically. + + .set HID0_ICFI, 0x0800 // I-Cache Flash Invalidate + .set HID0, 1008 // SPR # for HID0 + .set BLOCK_SIZE, 32 + .set BLOCK_LOG2, 5 // Should be == log2(BLOCK_SIZE) + .set BASE, 0x80000000 // base addr of valid cacheable region + +//++ +// +// Routine Description: +// +// The D-Cache is flushed by loading 1 byte per cache line from a +// valid address range, then flushing that address range. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalSweepDcache) + + mfsprg r.5, 1 // Get PCR->FirstLevelDcacheSize + lwz r.4, PcFirstLevelDcacheSize(r.5) + + LWI (r.3, BASE) // Get a valid virtual address + srwi r.4, r.4, BLOCK_LOG2 // Convert to # cache lines +// +// Load r.4 cache lines starting from virtual address in r.3 +// + mtctr r.4 + DISABLE_INTERRUPTS(r.10,r.12) + sync // ensure ALL previous stores completed + subi r.6, r.3, BLOCK_SIZE // bias addr for pre-index +FillLoop: + lbzu r.0, BLOCK_SIZE(r.6) // Read memory to force cache fill + bdnz FillLoop // into cache + ENABLE_INTERRUPTS(r.10) + + mtctr r.4 +FlushRange: + dcbf r.0, r.3 // flush block + addi r.3, r.3, BLOCK_SIZE // bump address + bdnz FlushRange + + LEAF_EXIT(HalSweepDcache) + + + + + +//++ +// +// Routine Description: +// +// The I-Cache is flushed by toggling the Icache flash invalidate bit +// in HID0. Invalidation is all that is necessary. Flushing to main +// memory is not needed since the Icache can never be dirty. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalSweepIcache) + + LWI (r.3, BASE) + +FlashInvalidateIcache: + mfspr r.3, HID0 + ori r.4, r.3, HID0_ICFI // Cache Flash Invalidate + isync + mtspr HID0, r.4 // Flash invalidate I-Cache + mtspr HID0, r.3 // re-enable (not needed on 604) + + LEAF_EXIT(HalSweepIcache) + +// +// Routine Description: +// +// The D-Cache is flushed by issuing a data cache block flush (DCBF) +// instruction for each data block in the range. +// +// Arguments: +// +// r.3 - Starting address +// r.4 - Length +// +// Return Value: +// +// None. +// +// + LEAF_ENTRY(HalSweepDcacheRange) + + andi. r.5, r.3, BLOCK_SIZE-1 // Get block offset of Start Addr + or. r.4, r.4, r.4 // Check for Length == 0 + addi r.4, r.4, BLOCK_SIZE-1 // bump Length by BLOCK_SIZE-1 + add r.4, r.4, r.5 + srwi r.4, r.4, BLOCK_LOG2 // Compute # of cache blocks to flush + mtctr r.4 + bne+ FlushRange // Branch if Length != 0 + + LEAF_EXIT(HalSweepDcacheRange) + + + +// +// Routine Description: +// +// The I-Cache is flushed by issuing a Instruction Cache Block +// Invalidate (ICBI) instruction for each data block in the range. +// If the range is large, the entire Icache can be invalidated by +// branching to FlashInvalidateIcache. +// +// Arguments: +// +// r.3 - Starting address +// r.4 - Length +// +// Return Value: +// +// None. +// +// + LEAF_ENTRY(HalSweepIcacheRange) + + andi. r.5, r.3, BLOCK_SIZE-1 // Get block offset of Start Addr + or. r.4, r.4, r.4 // Check for Length == 0 + addi r.4, r.4, BLOCK_SIZE-1 // bump Length by BLOCK_SIZE-1 + add r.4, r.4, r.5 + srwi r.4, r.4, BLOCK_LOG2 // Compute # of cache blocks to flush + beqlr- // return if Length == 0 + mtctr r.4 + +#if 0 +// +// Possible speedup: If Length is fairly large (e.g. greater than 1/2 +// of the cache size), we will flash invalidate the entire cache, else +// only sweep the desired range. +// + li r.5, 16384/BLOCK_SIZE // # Icache lines on 604 + cmpwi r.6, 3 // possible values are 3 or 4 + bgt Threshold // Branch if 604 + li r.5, 8192/BLOCK_SIZE // # Icache lines on 603 +Threshold: + srwi r.5, r.5, 1 // r.5 = IcacheLines/2 + cmpl 0,0, r.4, r.5 + bgt FlashInvalidateIcache +#endif + +InvalidateIcache: + icbi 0, r.3 // invalidate block in I-cache + addi r.3, r.3, BLOCK_SIZE // bump address by BLOCK_SIZE + bdnz InvalidateIcache + + LEAF_EXIT(HalSweepIcacheRange) + diff --git a/private/ntos/nthals/haleagle/ppc/pxcalstl.c b/private/ntos/nthals/haleagle/ppc/pxcalstl.c new file mode 100644 index 000000000..bc8044575 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxcalstl.c @@ -0,0 +1,184 @@ +/*++ + +Copyright (c) 1991-1993 Microsoft Corporation + Copyright 1994 MOTOROLA, INC. All Rights Reserved. This file + contains copyrighted material. Use of this file is restricted + by the provisions of a Motorola Software License Agreement. + +Module Name: + + pxcalstl.c + +Abstract: + + + This module implements the calibration of the stall execution HAL + service for a PowerPC system. + + +Author: + + David N. Cutler (davec) 26-Apr-1991 + Jim Wooldridge + Steve Johns (Motorola) + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "halp.h" +#include "pxsystyp.h" + +// +// KeQueryPerformanceCounter & KeStallExecutionProcessor are called +// before Phase 0 initialization, so initialize it to a reasonable value. +// +ULONG HalpPerformanceFrequency = 80000000/16; +extern ULONG HalpClockCount; +extern ULONG HalpFullTickClockCount; + + +// +// Put all code for HAL initialization in the INIT section. It will be +// deallocated by memory management when phase 1 initialization is +// completed. +// + +#if defined(ALLOC_PRAGMA) + +#pragma alloc_text(INIT, HalpCalibrateStall) + +#endif + + + +ULONG +HalpCalibrateTBPStack( + VOID + ); + + +BOOLEAN +HalpCalibrateStall ( + VOID + ) + +/*++ + +Routine Description: + + This function calibrates the stall execution HAL service. + + N.B. This routine is only called during phase 1 initialization. + +Arguments: + + None. + +Return Value: + + A value of TRUE is returned if the calibration is successfully + completed. Otherwise a value of FALSE is returned. + +--*/ + +{ int i; + ULARGE_INTEGER BigNumber; + ULONG Variance; + ULONG BusSpeed; + static ULONG BusSpeeds [] = { + 25000000, + 33333333, + 40000000, + 41875000, + 50000000, + 55833333, + 60000000, + 66000000, + 66666666, + 67000000, + 75000000, + 80000000, + 83333333, + 83750000, + 90000000, + 99000000, + 100000000, + 111666666, + 120000000, + 132000000, + 133333332, + 134000000, + 150000000, + 160000000, + 166666666, + 167500000 + }; + + + + // + // Set initial scale factor + // + + PCR->StallScaleFactor = 1; + + // + // Compute the clock frequency of the Time Base & Decrementer + // + // It's possible for reads from the CMOS RTC to return odd results. + // For this reason, We can use a do-while loop, to ensure the calibration + // function is called at least once and is returning a reasonable value. + // + + do { + switch( HalpSystemType ) { + + case MOTOROLA_POWERSTACK: + HalpPerformanceFrequency = HalpCalibrateTBPStack(); + break; + + default: + case MOTOROLA_BIG_BEND: + HalpPerformanceFrequency = HalpCalibrateTB(); + break; + } + } while( HalpPerformanceFrequency < 1000000 ); + + // + // CPU bus runs at 4 times the DECREMENTER frequency + // + BusSpeed = HalpPerformanceFrequency * 4; + + // + // Choose the bus speed which is closest to calculated value. + // If the bus speed is not "close enough", then it may be + // a new speed which we don't know about. For this case + // we will leave the Performance Frequency alone. + // + for (i=0; i< (sizeof(BusSpeeds)/sizeof(ULONG)); i++) { + // + // We are going to allow for a 0.1% variation + // in calibrated frequency of the system bus clock. + // Calculate the variance as 1/2048 the frequency. + // + Variance = BusSpeeds[i] >> 11; + if ((BusSpeeds[i] - Variance < BusSpeed) && + (BusSpeeds[i] + Variance > BusSpeed)) { + HalpPerformanceFrequency = BusSpeeds[i] / 4; + break; + } + } + + // + // Initialize the system clock variables + // + HalpClockCount = (HalpPerformanceFrequency * (MAXIMUM_INCREMENT/10000)) / 1000; + HalpFullTickClockCount = HalpClockCount; + + return TRUE; +} diff --git a/private/ntos/nthals/haleagle/ppc/pxcirrus.h b/private/ntos/nthals/haleagle/ppc/pxcirrus.h new file mode 100644 index 000000000..5ec9916ba --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxcirrus.h @@ -0,0 +1,238 @@ +/* + * pxcirrus.h + * + * Defines for cirrus HAL support + */ + +#define CIRRUS_VIDEO_MEMORY_BASE 0xc0000000 +#define CIRRUS_VENDOR_ID 0x1013 +#define CIRRUS_COMMAND_MASK 0x03 + +#define CIRRUS_TEXT_MEM 0xb8000 +#define CIRRUS_FONT_MEM 0xa0000 + + +#define WRITE_CIRRUS_UCHAR(port,data) \ + *(volatile unsigned char *) \ + ((ULONG)HalpIoControlBase+(port))=(UCHAR)(data), \ + KeFlushWriteBuffer() + +#define WRITE_CIRRUS_VRAM(port,data) \ + *((PUCHAR)((ULONG) HalpVideoMemoryBase + (port))) = (UCHAR) (data), \ + KeFlushWriteBuffer() + +#define WRITE_CIRRUS_USHORT(port,data) \ + *(volatile unsigned short*) \ + ((ULONG)HalpIoControlBase+(port))=(USHORT)(data), \ + KeFlushWriteBuffer() + +#define READ_CIRRUS_VRAM(port) \ + *(HalpVideoMemoryBase + (port)) + +#define READ_CIRRUS_UCHAR(port) \ + *(volatile unsigned char *)((ULONG)HalpIoControlBase + (port)) + +#define setreg(port,index,data) \ + WRITE_CIRRUS_UCHAR(port,index), \ + WRITE_CIRRUS_UCHAR(port+1,data) + +#define outportb(port,data) \ + WRITE_CIRRUS_UCHAR(port,data) + +#define outp(port,data) outportb(port,data) + +#define inp(port) \ + READ_CIRRUS_UCHAR(port) + +#define INSTATUS_1 (PVOID) ((ULONG)((int)HalpIoControlBase + (int)0x03DA)) + +// +// Attributes Registers +// + +static unsigned char attr3[] = +{ + 0x00, // AR0-ARF: Attribute Controller + 0x01, // Palette Registers + 0x02, + 0x03, + 0x04, + 0x05, + 0x14, + 0x07, + 0x38, + 0x39, + 0x3a, + 0x3b, + 0x3c, + 0x3d, + 0x3e, + 0x3f, + 0x0c, // AR10: Attribute Controller Mode + // Blink Enable + // Line Graphics Enable + 0x00, // AR11: Overscan (Border) color + 0x0f, // AR12: Color Plane Enable + // All planes enabled + 0x08, // AR13: Pixel Panning + 0x00 // AR14: Color Select +}; + +// +// CRT control +// + +static unsigned char crtc3[] = +{ + 0x5f, // CR0: Horizontal Total + 0x4f, // CR1: Horizontal Display End + 0x50, // CR2: Start Horizontal Blinking + 0x82, // CR3: End Horizontal Blanking + 0x55, // CR4: Start Horizontal Retrace Pulse + 0x81, // CR5: End Horizontal Retrace Pulse + 0xbf, // CR6: Vertical Total + 0x1f, // CR7: Overflow + 0x00, // CR8: Row Scan + 0x4f, // CR9: Character Cell Height (16) + 0x0d, // CRa: Text Cursor Start Register + 0x0e, // CRb: Text Cursor End Register + 0x00, // CRc: Screen Start High + 0x00, // CRd: Screen Start Low + 0x00, // CRe: Text Cursor Location High + 0x00, // CRf: Text Cursor Location Low + 0x9c, // CR10: Vertical Sync Start + 0xae, // CR11: Vertical Sync End + 0x8f, // CR12: Vertical Display End + 0x28, // CR13: Offset + 0x1f, // CR14: Underline Row Scanline + 0x96, // CR15: Vertical Blank Start + 0xb9, // CR16: Vertical Blank End + 0xa3, // CR17: Mode Control + 0xff, // CR18: Line Compare + 0x00, // CR19: Interlace End + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00 +}; + + +// +// Graphics Registers +// + +static unsigned char graph3[] = +{ + 0x00, // GR0: Set/Reset Register + 0x00, // GR1: Set/Reset Enable Register + 0x00, // GR2: Color Compare + 0x00, // GR3: Data Rotate Register + 0x00, // GR4: Read Map Select Register + 0x10, // GR5: Mode Register (Odd/Even On) + + 0x0e, // GR6: Miscellaneous Register + // Memory Map b800:0 + // Chain Odd Maps to Even + 0x00, // GR7: Color Don't Care register + 0xff // GR8: Bit Mask Register +}; + +// +// Sequencer Registers +// + +static unsigned char seq3[] = +{ + 0x03, // SR0: Reset Register + // Asynchronous and Synchronous reset + 0x00, // SR1: Clocking Mode + 0x03, // SR2: Plane Mask Register + // Map 0 and 1 Enable + 0x00, // SR3: Character Map Select Register + 0x02, // SR4: Memory Mode + // Extended Memory +}; + +// +// Extended Sequencer Registers +// + +static unsigned char eseq3[] = +{ + 0x02,0x0f, // Enable Writing Pixel Extension + 0x06,0x12, // Unlock All Extensions + 0x07,0x00, // Extended Sequencer Mode (From Meeting) + 0x08,0x40, // EEPROM control register + +// +// The Cirrus book says that all of the scratch pad registers +// are "reserved for the Cirrus Logic BIOS" so it would be proper to +// leave all of them alone. +// + +// 0x09,0x68, // Scratch Pad 0 register +// 0x0a,0x32, // Scratch Pad 1 register + 0x0b,0x4a, // VCLK 0 Numerator Register + 0x0c,0x5b, // VCLK 1 Numerator Register + 0x0d,0x42, // VCLK 2 Numerator Register + 0x0e,0x6e, // VCLK 3 Numerator Register + 0x0f,0x1d, // DRAM control + 0x10,0x00, // Graphics Cursor X Position + 0x11,0x00, // Graphics Cursor Y Position + 0x12,0x00, // Graphics Cursor Attributes + 0x13,0x00, // Graphics Pattern Address Offset Register +// 0x14,0x00, // Scratch Pad Register 2 +// 0x15,0x02, // Scratch Pad Register 3 + 0x16,0x71, // Performance Tuning + 0x17,0x31, // Configuration Readback and Extended Control + 0x18,0x00, // Signature Generator Control + 0x19,0x01, // Signature Register Result Low-Byte + 0x1a,0x00, // Signature Generator Result High-Byte + 0x1b,0x2b, // VCLK Denominator and Post-Scalar Value + 0x1c,0x2f, + 0x1d,0x1f, + 0x1e,0x2a, + 0x1f,0x1c, // MCLK Select Register + 0xff // End of list. +}; + +// +// Extended CRTC Registers +// + +static unsigned char ecrtc3[] = +{ + 0x19,0x00, // CR19: Inerlace End + 0x1a,0x00, // CR1a: Miscellaneous + 0x1b,0x00, // CR1b: Extended Display Controlls + 0x1d,0x00, // Overlay Extended Control + 0xff // End of list. +}; + +// +// Extended Graphics Registers +// + +static unsigned char egraph3[] = +{ + 0x9,0x00, // GR9: Offset Register 0 + 0xa,0x00, // GRa: Offset Register 1 + 0xb,0x00, // GRb: Graphics Controller Mode Extnsions + 0xc,0xff, // GRc: Color Key Compare + 0xd,0x00, // GRd: Color Key Compare Mask + 0x10,0x00, // GR10: Background Color Byte 1 + 0x11,0x00, // GR11: Foreground Color Byte 1 + 0xff +}; + +// +// Extended Attribute Registers +// + +static unsigned char eattr3[] = +{ + 0xff +}; + diff --git a/private/ntos/nthals/haleagle/ppc/pxclksup.s b/private/ntos/nthals/haleagle/ppc/pxclksup.s new file mode 100644 index 000000000..140c8fbee --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxclksup.s @@ -0,0 +1,145 @@ +/*********************************************************************** + + Copyright 1994 MOTOROLA, INC. All Rights Reserved. This file + contains copyrighted material. Use of this file is restricted + by the provisions of a Motorola Software License Agreement. + + File Name: + PXCLKSUP.S + + Globals: + none + + Functions: + HalpUpdateDecrementer + KeQueryPerformanceCounter + + History: + 11-Feb-1994 Steve Johns + Original Version + 23-Jun-1994 Steve Johns (sjohns@pets.sps.mot.com) + Fixed HalpZeroPerformanceCounter. Was writing to RTCU & RTCL. + Writes should go to SPR 20 & 21. + 11-Sep-1995 Steve Johns + Removed 601 specific code + Removed 603 workaround, since we don't support < 603 v3.2 +***********************************************************************/ + +#include <halppc.h> +#define ERRATA603 FALSE + + + LEAF_ENTRY(HalpSetDecrementer) + + mtdec r.3 // Set the DECREMENTER + + LEAF_EXIT(HalpSetDecrementer) + + + + LEAF_ENTRY(HalpUpdateDecrementer) + +// +// Read the DECREMENTER to get the interrupt latency and bias Count by +// that amount. Otherwise, the latencies would accumulate and the time +// of day would run slow. +// + mfdec r.7 // Read the DECREMENTER + add r.4,r.3,r.7 // + Count +// +// We expect that the DECREMENTER should be near 0xFFFFFFxx, so R4 should +// be less than r.3. If not, we don't want to cause an excessively long +// clock tick, so just ignore the latency and use Count. +// + cmpl 0,0,r.4,r.3 + ble SetDecr + mr r.4,r.3 +SetDecr: + + mtdec r.4 // Write to the DECREMENTER +#if ERRATA603 + isync +#endif + +// Undocumented return value: the latency in servicing this interrupt + neg r.3,r.7 + + + LEAF_EXIT(HalpUpdateDecrementer) + + + + .extern HalpPerformanceFrequency + + +/*********************************************************************** + Synopsis: + ULARGE_INTEGER KeQueryPerformanceCounter ( + OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL) + + Purpose: + Supplies a 64-bit realtime counter for use in evaluating performance + of routines. + + Returns: + This routine returns current 64-bit performance counter and, + optionally, the frequency of the Performance Counter. + + Global Variables Referenced: + HalpPerformanceFrequency + +***********************************************************************/ + +// +// Register Definitions +// + .set RetPtr, r.3 + .set Freq, r.4 + .set TimerLo, r.6 + .set TimerHi, r.7 + .set Temp, r.8 + + + LEAF_ENTRY(KeQueryPerformanceCounter) + + + cmpli 0,0,Freq,0 // Was PerformanceFrequency passed ? + beq ReadTB + + lwz Temp,[toc]HalpPerformanceFrequency(r.toc) + lwz Temp,0(Temp) // PerformanceFrequency.LowPart = + stw Temp,0(Freq) // HalpPerformanceFrequency; + li Temp,0 // PerformanceFrequency.HighPart = 0; + stw Temp,4(Freq) + +ReadTB: + mftbu TimerHi // Read the TB registers coherently + mftb TimerLo +#if ERRATA603 + mftb TimerLo + mftb TimerLo + mftb TimerLo +#endif + mftbu Temp + cmpl 0,0,Temp,TimerHi + bne- ReadTB + + stw TimerLo,0(RetPtr) + stw TimerHi,4(RetPtr) + + LEAF_EXIT(KeQueryPerformanceCounter) + + + + .set TB, 284 + .set TBU, 285 + + LEAF_ENTRY(HalpZeroPerformanceCounter) + + li r.3, 0 + mtspr TB,r.3 + mtspr TBU,r.3 + + LEAF_EXIT(HalpZeroPerformanceCounter) + + diff --git a/private/ntos/nthals/haleagle/ppc/pxclock.c b/private/ntos/nthals/haleagle/ppc/pxclock.c new file mode 100644 index 000000000..a621530d3 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxclock.c @@ -0,0 +1,243 @@ + +/***************************************************************************** + + Copyright 1994 MOTOROLA, INC. All Rights Reserved. This file + contains copyrighted material. Use of this file is restricted + by the provisions of a Motorola Software License Agreement. + +Module Name: + + PXCLOCK.C + +Abstract: + + This module contains the system clock interrupt handler. + The DECREMENTER is used to implement the system clock. The + handler resets the DECREMENTER to SYSTEM_TIME (accounting + for interrupt latency), and updates the system time. + + +Author: + + Steve Johns 10-Feb-1994 + +Revision History: +// 09-Jun-95 Steve Johns +// - Removed 1 level of buffering of time increment to match +// buffering of DECREMENTER counts. +******************************************************************************/ + +#include "halp.h" + +extern ULONG HalpPerformanceFrequency; + +BOOLEAN +KdPollBreakIn ( + VOID + ); + +ULONG HalpClockCount; +ULONG HalpFullTickClockCount; +ULONG HalpUpdateDecrementer(); + +ULONG HalpCurrentTimeIncrement; +ULONG HalpNewTimeIncrement; + +BOOLEAN +HalpHandleDecrementerInterrupt( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext, + IN PVOID TrapFrame + ) + +/*++ + +Routine Description: + + Clock interrupt handler for processor 0. + +Arguments: + + Interrupt + + ServiceContext + + TrapFrame + +Return Value: + + TRUE + +--*/ +{ + KIRQL OldIrql; + + // + // Raise irql via updating the PCR + // + + OldIrql = PCR->CurrentIrql; + + PCR->CurrentIrql = CLOCK2_LEVEL; + + // + // Reset DECREMENTER, accounting for interrupt latency. + // + + HalpUpdateDecrementer(HalpClockCount); + + // + // Call the kernel to update system time + // + + KeUpdateSystemTime(TrapFrame,HalpCurrentTimeIncrement); + + // + // If tick rate has changed, then tell the kernel about it + // + + HalpCurrentTimeIncrement = HalpNewTimeIncrement; + + // + // Lower Irql to original value and enable interrupts + // + + PCR->CurrentIrql = OldIrql; + + HalpEnableInterrupts(); + + if ( KdDebuggerEnabled && KdPollBreakIn() ) { + DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C); + } + + return (TRUE); +} + +#if !defined(NT_UP) +VOID +HalpHandleDecrementerInterrupt1( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext, + IN PVOID TrapFrame + ) + +/*++ + +Routine Description: + + Clock interrupt handler for processors other than 0. + +Arguments: + + Interrupt + + ServiceContext + + TrapFrame + +Return Value: + + TRUE + +--*/ +{ + + KIRQL OldIrql; + + // + // Raise irql via updating the PCR + // + + OldIrql = PCR->CurrentIrql; + + PCR->CurrentIrql = CLOCK2_LEVEL; + + // + // Reset DECREMENTER, accounting for interrupt latency. + // + + HalpUpdateDecrementer(HalpFullTickClockCount); + + // + // Call the kernel to update run time for this thread and process. + // + + KeUpdateRunTime(TrapFrame); + + // + // Lower Irql to original value + // + + PCR->CurrentIrql = OldIrql; + + return; +} +#endif + +ULONG +HalSetTimeIncrement ( + IN ULONG DesiredIncrement + ) + +/*++ + +Routine Description: + + This function is called to set the clock interrupt rate to the frequency + required by the specified time increment value. + + N.B. This function is only executed on the processor that keeps the + system time. + +Arguments: + + DesiredIncrement - Supplies desired number of 100ns units between clock + interrupts. + +Return Value: + + The actual time increment in 100ns units. + +--*/ + +{ + + 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); + + // + // HalpPerformanceFrequence is the number of times the decrementer + // ticks in 1 second. MINIMUM_INCREMENT is the number of 100 is the + // number of 100ns units in 1 ms. + // Therefore, DesiredIncrement/MINUMUM_INCREMENT is the number of + // ms desired. This multiplied by the number of decrementer ticks + // in 1 second, divided by 1000 gives the number of ticks in the + // desired number of milliseconds. This value will go into the + // decrementer. + // + + HalpClockCount = (HalpPerformanceFrequency * + (DesiredIncrement/MINIMUM_INCREMENT)) / 1000; + + // + // Calculate the number of 100ns units to report to the kernel every + // time the decrementer fires with this new period. Note, for small + // values of DesiredIncrement (min being 10000, ie 1ms), truncation + // in the above may result in a small decrement in the 5th decimal + // place. As we are effectively dealing with a 4 digit number, eg + // 10000 becomes 9999.something, we really can't do any better than + // the following. + // + + HalpNewTimeIncrement = DesiredIncrement/MINIMUM_INCREMENT * MINIMUM_INCREMENT; + + KeLowerIrql(OldIrql); + return HalpNewTimeIncrement; +} diff --git a/private/ntos/nthals/haleagle/ppc/pxdat.c b/private/ntos/nthals/haleagle/ppc/pxdat.c new file mode 100644 index 000000000..cb05bec92 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxdat.c @@ -0,0 +1,110 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + pxdat.c + +Abstract: + + Declares various data which is initialize data, or pagable data. + +Author: + +Environment: + + Kernel mode only. + +Revision History: + + Jim Wooldridge Ported to PowerPC + +--*/ + +#include "halp.h" + +#ifdef ALLOC_DATA_PRAGMA +#pragma data_seg("INIT") +#endif + +// +// The following data is only valid during system initialiation +// and the memory will be re-claimed by the system afterwards +// + +ADDRESS_USAGE HalpDefaultIoSpace = { + NULL, CmResourceTypePort, InternalUsage, + { + 0x000, 0x10, // SIO DMA + 0x0C0, 0x20, // SIO DMA + 0x080, 0x20, // SIO DMA + 0x400, 0x40, // SIO DMA + 0x480, 0x10, // SIO DMA + 0x4C0, 0x10, // SIO DMA + 0x4D6, 0x2, // SIO DMA + + 0x020, 0x2, // PIC + 0x0A0, 0x2, // Cascaded PIC + 0x4D0, 0x2, // PIC edge/level + + 0x040, 0x4, // Timer1, Referesh, Speaker, Control Word + + 0x061, 0x1, // NMI (system control port B) + 0x092, 0x1, // system control port A + + 0x070, 0x2, // Cmos/NMI enable + + 0x074, 0x4, // NVRAM + + 0x0F0, 0x10, // coprocessor ports + +// 0x800, 0x1, // Big Bend NVRAM data port + 0x81C, 0x1, // Eagle external configuration register + 0x850, 0x1, // Eagle external configuration register +// 0xC00, 0x2, // Big Bend NVRAM index ports + 0xCF8, 0x8, // PCI CONFIG_ADDRESS & CONFIG_DATA + + 0,0 + } +}; + + +// +// From usage.c +// + +ADDRESS_USAGE *HalpAddressUsageList; + +// +// Misc hal stuff in the registry +// + +WCHAR rgzHalClassName[] = L"Hardware Abstraction Layer"; + + +// +// From ixpcibus.c +// + +WCHAR rgzMultiFunctionAdapter[] = L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter"; +WCHAR rgzConfigurationData[] = L"Configuration Data"; +WCHAR rgzIdentifier[] = L"Identifier"; +WCHAR rgzPCIIndetifier[] = L"PCI"; + + +// +// From ixpcibrd.c +// + +WCHAR rgzReservedResources[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\SystemResources\\ReservedResources"; + +#ifdef ALLOC_DATA_PRAGMA +#pragma data_seg() +#endif + +// +// IDT vector usage info +// + +IDTUsage HalpIDTUsage[MAXIMUM_IDTVECTOR]; diff --git a/private/ntos/nthals/haleagle/ppc/pxdisp.c b/private/ntos/nthals/haleagle/ppc/pxdisp.c new file mode 100644 index 000000000..d86393105 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxdisp.c @@ -0,0 +1,2211 @@ +/*++ +Copyright (c) 1994 International Business Machines Corporation + +Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +contains copyrighted material. Use of this file is restricted +by the provisions of a Motorola Software License Agreement. + +Module Name: + +pxdisp.c + +Abstract: + + This module implements the HAL display initialization and output routines + for a Eagle-Based PowerPC system using an S3, Weitek P9000, Cirrus + CL-GD5434 video adapter, or most any video card with an option ROM. + +Author: + + Jim Wooldridge Sept 1994 - Ported to PowerPC Initial Version + +Environment: + + Kernel mode + +Revision History: + + Jess Botts S3 support in text mode Oct-1993 + Lee Nolan Added Weitek P9000 support Feb-1994 + Mike Haskell Added Weitek P9100 support Oct-1994 + +--*/ + +#include "halp.h" +#include "pxs3.h" +#include "string.h" +#include "pxcirrus.h" +#include "pxpcisup.h" + +//============================================================================= +// +// IBMBJB added include to get text mode values for the Brooktree 485 DAC's +// palette registers, removed definition of HDAL and added address +// definitions for PowerPC + +#include "txtpalet.h" + +#if defined(_PPC_) + +# define MEMORY_PHYSICAL_BASE VIDEO_MEMORY_BASE +# define CONTROL_PHYSICAL_BASE VIDEO_CONTROL_BASE + +#endif + +//PHYSICAL ADDRESS of WEITEK P9000 video ram +#define P9_VIDEO_MEMORY_BASE 0xC1200000 + +//PHYSICAL ADDRESS of WEITEK P9100 video ram +#define P91_VIDEO_MEMORY_BASE 0xC1800000 + +//PHYSICAL ADDRESS of S3 video ram +#define S3_VIDEO_MEMORY_BASE 0xC0000000 + + +#define ROWS 25 +#define COLS 80 +#define TAB_SIZE 4 +#define ONE_LINE (COLS*2) +#define TWENTY_FOUR_LINES (ROWS-1)* ONE_LINE +#define TWENTY_FIVE_LINES ROWS * ONE_LINE +#define TEXT_ATTR 0x1F + +// +// Define forward referenced procedure prototypes. +// +VOID HalpDisplayINT10Setup (VOID); + +VOID HalpOutputCharacterINT10 ( + IN UCHAR Character ); + +VOID HalpScrollINT10 ( + IN UCHAR line + ); + +VOID HalpDisplayCharacterVGA ( + IN UCHAR Character ); + + +VOID +HalpDisplayCharacterS3 ( + IN UCHAR Character + ); + +VOID +HalpOutputCharacterS3 ( + IN UCHAR AsciiChar + ); + +VOID +HalpDisplayPpcS3Setup ( + VOID + ); + +VOID +HalpScrollS3( + IN UCHAR line + ); + +VOID +HalpDisplayPpcP9Setup ( + VOID + ); + +VOID +HalpDisplayCharacterP9 ( + IN UCHAR Character + ); + +VOID +HalpDisplayPpcP91Setup ( + VOID + ); + +VOID +HalpDisplayCharacterP91 ( + IN UCHAR Character + ); + + +VOID +WaitForVSync ( + VOID + ); + +VOID +ScreenOn ( + VOID + ); + +VOID +ScreenOff ( + VOID + ); + +VOID +Scroll_Screen ( + IN UCHAR line + ); + +VOID +HalpDisplayPpcP9Setup ( + VOID + ); + +VOID +HalpDisplayCharacterP9 ( + IN UCHAR Character + ); + +VOID +HalpOutputCharacterP9( + IN PUCHAR Glyph + ); + +VOID +HalpDisplayPpcP91Setup ( + VOID + ); + +VOID +HalpDisplayCharacterP91 ( + IN UCHAR Character + ); + +VOID +HalpOutputCharacterP91( + IN PUCHAR Glyph + ); + + + + +VOID +HalpDisplayCharacterCirrus ( + IN UCHAR Character + ); + +VOID +HalpOutputCharacterCirrus ( + IN UCHAR AsciiChar + ); + +VOID +HalpDisplayPpcCirrusSetup ( + VOID + ); + +VOID HalpScrollCirrus ( + IN UCHAR line + ); + + +BOOLEAN +HalpInitializeX86DisplayAdapter( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ); + +static void updattr(IN int rg,IN unsigned char val); +static void set_ext_regs(IN int reg,IN unsigned char *p); +static void clear_text(VOID); +static void load8x16(VOID); +static void load_ramdac(); + + +// +// +// +typedef +VOID +(*PHALP_CONTROLLER_SETUP) ( + VOID + ); + +typedef +VOID +(*PHALP_DISPLAY_CHARACTER) ( + UCHAR + ); +typedef +VOID +(*PHALP_SCROLL_SCREEN) ( + UCHAR + ); + + +typedef +VOID +(*PHALP_OUTPUT_CHARACTER) ( + UCHAR + ); + + +// +// Define static data. +// +BOOLEAN HalpDisplayOwnedByHal; +PHAL_RESET_DISPLAY_PARAMETERS HalpResetDisplayParameters = NULL; + +volatile PUCHAR HalpVideoMemoryBase = (PUCHAR)0; + +PHALP_CONTROLLER_SETUP HalpDisplayControllerSetup = NULL; +PHALP_DISPLAY_CHARACTER HalpDisplayCharacter = NULL; +PHALP_OUTPUT_CHARACTER HalpOutputCharacter = NULL; +PHALP_SCROLL_SCREEN HalpScrollScreen = NULL; + + +// +// Define OEM font variables. +// + +USHORT HalpBytesPerRow; +USHORT HalpCharacterHeight; +USHORT HalpCharacterWidth; +ULONG HalpDisplayText; +ULONG HalpDisplayWidth; +ULONG HalpScrollLength; +ULONG HalpScrollLine; + +// +// Define display variables. +// +ULONG HalpColumn; +ULONG HalpRow; +USHORT HalpHorizontalResolution; +USHORT HalpVerticalResolution; +USHORT HalpScreenStart = 0; + + +BOOLEAN HalpDisplayTypeUnknown = FALSE; + +POEM_FONT_FILE_HEADER HalpFontHeader; + + +BOOLEAN +HalpInitializeDisplay ( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ) + +/*++ + +Routine Description: + + This routine maps the video memory and control registers into the user + part of the idle process address space, initializes the video control + registers, and clears the video screen. + +Arguments: + + LoaderBlock - Supplies a pointer to the loader parameter block. + +Return Value: + + If the initialization is successfully completed, than a value of TRUE + is returned. Otherwise, a value of FALSE is returned. + +--*/ + +{ + PCONFIGURATION_COMPONENT_DATA ConfigurationEntry; + ULONG MatchKey; + //LONG SlotNumber = 0; + //LONG ChipID = -1; + + + + + + // + // For the Weitek P9000, set the address of the font file header. + // Display variables are computed later in HalpDisplayPpcP9Setup. + // + HalpFontHeader = (POEM_FONT_FILE_HEADER)LoaderBlock->OemFontFile; + + + // + // Read the Registry entry to find out which video adapter the system + // is configured for. This code depends on the OSLoader to put the + // correct value in the Registry. + // + MatchKey = 0; + ConfigurationEntry=KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot, + ControllerClass, + DisplayController, + &MatchKey); + + while (ConfigurationEntry != NULL) { + + HalpDisplayCharacter = HalpDisplayCharacterVGA; + HalpOutputCharacter = HalpOutputCharacterS3; + HalpScrollScreen = HalpScrollS3; + + + + if (ConfigurationEntry->ComponentEntry.Identifier[0] == 'C' && + ConfigurationEntry->ComponentEntry.Identifier[1] == 'L' && + ConfigurationEntry->ComponentEntry.Identifier[2] == '5' && + ConfigurationEntry->ComponentEntry.Identifier[3] == '4') { + HalpDisplayControllerSetup = HalpDisplayPpcCirrusSetup; + HalpDisplayCharacter = HalpDisplayCharacterCirrus; + HalpScrollScreen = HalpScrollCirrus; + break; + } + if (HalpInitializeX86DisplayAdapter(LoaderBlock)) { + HalpDisplayControllerSetup = HalpDisplayINT10Setup; + HalpDisplayCharacter = HalpDisplayCharacterVGA; + HalpOutputCharacter = HalpOutputCharacterINT10; + HalpScrollScreen = HalpScrollINT10; + break; + } + + if (ConfigurationEntry->ComponentEntry.Identifier[0] == 'S' && + ConfigurationEntry->ComponentEntry.Identifier[1] == '3') { + HalpDisplayControllerSetup = HalpDisplayPpcS3Setup; + break; + } + + if (!strcmp(ConfigurationEntry->ComponentEntry.Identifier,"P9000")) { + HalpDisplayControllerSetup = HalpDisplayPpcP9Setup; + HalpDisplayCharacter = HalpDisplayCharacterP9; + break; + } + + if (!strcmp(ConfigurationEntry->ComponentEntry.Identifier,"P9100")) { + HalpDisplayControllerSetup = HalpDisplayPpcP91Setup; + HalpDisplayCharacter = HalpDisplayCharacterP91; + break; + } + + break; + + } // end While + + + + // + // Initialize the display controller. + // + + if (HalpDisplayControllerSetup != NULL) { + HalpDisplayControllerSetup(); + } + + return TRUE; +} + +VOID +HalAcquireDisplayOwnership ( + IN PHAL_RESET_DISPLAY_PARAMETERS ResetDisplayParameters + ) + +/*++ + +Routine Description: + + This routine switches ownership of the display away from the HAL to + the system display driver. It is called when the system has reached + a point during bootstrap where it is self supporting and can output + its own messages. Once ownership has passed to the system display + driver any attempts to output messages using HalDisplayString must + result in ownership of the display reverting to the HAL and the + display hardware reinitialized for use by the HAL. + +Arguments: + + ResetDisplayParameters - if non-NULL the address of a function + the hal can call to reset the video card. The function returns + TRUE if the display was reset. + +Return Value: + + None. + +--*/ + +{ + + // + // Record the routine to reset display to text mode. + // + HalpResetDisplayParameters = ResetDisplayParameters; + + // + // Set HAL ownership of the display to FALSE. + // + + HalpDisplayOwnedByHal = FALSE; + return; +} + + +VOID +HalpDisplayPpcS3Setup ( + VOID + ) +/*++ + +Routine Description: + This routine initializes the S3 display controller chip. +Arguments: + None. +Return Value: + None. + +--*/ +{ +// +// Routine Description: +// +// This is the initialization routine for S3 86C911. This routine initializes +// the S3 86C911 chip in the sequence of VGA BIOS for AT. +// + ULONG DataLong; + USHORT i,j; + UCHAR DataByte; + UCHAR Index; +// PVOID Index_3x4, Data_3x5; + ULONG MemBase; + + + if (HalpVideoMemoryBase == NULL) { + + HalpVideoMemoryBase = (PUCHAR)KePhase0MapIo(S3_VIDEO_MEMORY_BASE, + 0x400000); // 4 MB + } + + // Enable Video Subsystem + // According to chapter 5.4.2 regular VGA setup sequence + + //========================================================================= + // + // IBMBJB changed from writing 0x10 and then 0x08 to writing 0x18 + // because the second write will wipe out the first one, the + // second write was originally done after the write to Setup_OP + // + // WRITE_S3_UCHAR(SUBSYS_ENB, 0x10); + // WRITE_S3_UCHAR(SUBSYS_ENB, 0x08); + + WRITE_S3_UCHAR(SUBSYS_ENB, 0x18); + + //========================================================================= + + // Subsystem Enable = 0x10; + WRITE_S3_UCHAR(Setup_OP, 0x01); + + WRITE_S3_UCHAR(DAC_Mask, 0x0); // Set screen into blank + WRITE_S3_UCHAR(Seq_Index, 0x01); + WRITE_S3_UCHAR(Seq_Data, 0x21); + + //========================================================================= + // + // IBMBJB removed this section because it is not currently used, this + // was left commented out instead of deleting it in case we use + // a monochrome monitor in the future + // + // // Check monitor type to decide index address (currently not use) + // DataByte = READ_S3_UCHAR(MiscOutR); + // ColorMonitor = DataByte & 0x01 ? TRUE : FALSE; + // + // if (ColorMonitor) { + // Index_3x4 = (PVOID)S3_3D4_Index; + // Data_3x5 = (PVOID)S3_3D5_Data; + // } else { + // Index_3x4 = (PVOID)Mono_3B4; + // Data_3x5 = (PVOID)Mono_3B5; + // } + // + //========================================================================= + + // + // -- Initialization Process Begin -- + // According to appendix B-4 "ADVANCED PROGRAMMER'S GUIDE TO THE EGA/VGA" + // to set the default values to VGA +3 mode. + // + WRITE_S3_UCHAR(VSub_EnB,VideoParam[0]); + // Note: Synchronous reset must be done before MISC_OUT write operation + + WRITE_S3_UCHAR(Seq_Index, RESET); // Synchronous Reset ! + WRITE_S3_UCHAR(Seq_Data, 0x01); + + // For ATI card(0x63) we may want to change the frequence + WRITE_S3_UCHAR(MiscOutW,VideoParam[1]); + + // Note: Synchronous reset must be done before CLOCKING MODE register is + // modified + WRITE_S3_UCHAR(Seq_Index, RESET); // Synchronous Reset ! + WRITE_S3_UCHAR(Seq_Data, 0x01); + + // Sequencer Register + for (Index = 1; Index < 5; Index++) { + WRITE_S3_UCHAR(Seq_Index, Index); + WRITE_S3_UCHAR(Seq_Data, VideoParam[SEQ_OFFSET+Index]); + } + + + // Set CRT Controller + // out 3D4, 0x11, 00 (bit 7 must be 0 to unprotect CRT R0-R7) + // UnLockCR0_7(); + WRITE_S3_UCHAR(S3_3D4_Index, VERTICAL_RETRACE_END); + DataByte = READ_S3_UCHAR(S3_3D5_Data); + DataByte = DataByte & 0x7f; + WRITE_S3_UCHAR(S3_3D5_Data, DataByte); + + // CRTC controller CR0 - CR18 + for (Index = 0; Index < 25; Index++) { + WRITE_S3_UCHAR(S3_3D4_Index, Index); + WRITE_S3_UCHAR(S3_3D5_Data, VideoParam[CRT_OFFSET+Index]); + } + + // attribute write + // program palettes and mode register + for (Index = 0; Index < 21; Index++) { + WaitForVSync(); + + DataByte = READ_S3_UCHAR(Stat1_In); // Initialize Attr. F/F + WRITE_S3_UCHAR(Attr_Index,Index); + KeStallExecutionProcessor(5); + + WRITE_S3_UCHAR(Attr_Data,VideoParam[ATTR_OFFSET+Index]); + KeStallExecutionProcessor(5); + + WRITE_S3_UCHAR(Attr_Index,0x20); // Set into normal operation + } + + WRITE_S3_UCHAR(Seq_Index, RESET); // reset to normal operation ! + WRITE_S3_UCHAR(Seq_Data, 0x03); + + // graphics controller + for (Index = 0; Index < 9; Index++) { + WRITE_S3_UCHAR(GC_Index, Index); + WRITE_S3_UCHAR(GC_Data, VideoParam[GRAPH_OFFSET+Index]); + } + + // turn off the text mode cursor + WRITE_S3_UCHAR(S3_3D4_Index, CURSOR_START); + WRITE_S3_UCHAR(S3_3D5_Data, 0x2D); + + // Unlock S3 specific registers + WRITE_S3_UCHAR(S3_3D4_Index, S3R8); + WRITE_S3_UCHAR(S3_3D5_Data, 0x48); + + // Unlock S3 SC registers + WRITE_S3_UCHAR(S3_3D4_Index, S3R9); + WRITE_S3_UCHAR(S3_3D5_Data, 0xa0); + + // Disable enhanced mode + WRITE_S3_UCHAR(ADVFUNC_CNTL, 0x02); + + // Turn off H/W Graphic Cursor + WRITE_S3_UCHAR(S3_3D4_Index, SC5); + WRITE_S3_UCHAR(S3_3D5_Data, 0x0); + + //========================================================================= + // + // IBMBJB S3 errata sheet says that CR40 can not be read correctly after + // power up until it has been written to, suggested workaround is + // to use the power on default (0xA4) Since the intent of the + // existing code was to reset bit 0, 0xA4 will be used to reset + // the bit. The other bits that are reset select the desired + // default configuration. + // + // If this register is written by the firmware then this fix is + // unneccessary. If future modifications of the firmware were to + // remove all writes to this register then this fix would have to + // be added here. This is being added now to protect this code + // from possible firmware changes. + // + // // Disable enhanced mode registers access + // WRITE_S3_UCHAR(S3_3D4_Index, SC0); + // DataByte = READ_S3_UCHAR(S3_3D5_Data); + // DataByte &= 0xfe; + // DataByte ^= 0x0; + // + // WRITE_S3_UCHAR(S3_3D5_Data, DataByte); + // + + WRITE_S3_UCHAR( S3_3D4_Index, SC0 ); + WRITE_S3_UCHAR( S3_3D5_Data, 0xA4 ); + + //========================================================================= + + // Set Misc 1 register + WRITE_S3_UCHAR(S3_3D4_Index, S3R0A); + DataByte = READ_S3_UCHAR(S3_3D5_Data); + DataByte &= 0xc7; + DataByte ^= 0x0; + WRITE_S3_UCHAR(S3_3D5_Data, DataByte); + + // Set S3R1 register + WRITE_S3_UCHAR(S3_3D4_Index, S3R1); + DataByte = READ_S3_UCHAR(S3_3D5_Data); + DataByte &= 0x80; + DataByte ^= 0x0; + WRITE_S3_UCHAR(S3_3D5_Data, DataByte); + + // Set S3R2 register + WRITE_S3_UCHAR(S3_3D4_Index, S3R2); + WRITE_S3_UCHAR(S3_3D5_Data, 0x0); + + // Set S3R4 register + WRITE_S3_UCHAR(S3_3D4_Index, S3R4); + DataByte = READ_S3_UCHAR(S3_3D5_Data); + DataByte &= 0xec; + DataByte ^= 0x0; + WRITE_S3_UCHAR(S3_3D5_Data, DataByte); + + //========================================================================= + // + // IBMBJB added this section to eliminate the DAC hardware cursor, this + // is done before setting registers 0x50 - 0x62 to default states + // so that R55's default state will not be undone. + // + // this sequence zeros the 2 least signifigant bits in command + // register 2 on the DAC + + WRITE_S3_UCHAR( S3_3D4_Index, 0x55 ); // set RS[3:2] to 10 + DataByte = READ_S3_UCHAR( S3_3D5_Data ); + DataByte &= 0xfc; + DataByte |= 0x02; + WRITE_S3_UCHAR( S3_3D5_Data, DataByte ); + + DataByte = READ_S3_UCHAR( DAC_Data ); + DataByte &= 0xfc; // zero CR21,20 in DAC command + WRITE_S3_UCHAR( DAC_Data, DataByte ); // register 2 + + //========================================================================= + // + // IBMBJB Added code to configure for 18 bit color mode and reload the + // palette registers because the firmware configures for 24 bit + // color. If this is done when the system driver initializes for + // graphics mode then the text mode colors can not be changed + // properly. + + WRITE_S3_UCHAR( S3_3D4_Index, 0x55 ); // RS[3:2] = 01B to address + WRITE_S3_UCHAR( S3_3D5_Data, 0x01 ); // DAC command register 0 + + DataByte = READ_S3_UCHAR( DAC_Mask ); // reset bit 1 in DAC command + DataByte &= 0xfd; // register 0 to select 6 bit + WRITE_S3_UCHAR( DAC_Mask, DataByte ); // operation (18 bit color) + + // IBMBJB added write to SDAC PLL control register to make sure CLK0 + // is correct if we have to reinitialize after graphics mode + // initialization, this does not bother the 928/Bt485 card + // because the Bt485 DAC looks very much like the SDAC + + WRITE_S3_UCHAR( DAC_WIndex, 0x0e ); // select SDAC PLL control reg + WRITE_S3_UCHAR( DAC_Data, 0x00 ); // select SDAC CLK0 + + WRITE_S3_UCHAR( S3_3D4_Index, 0x55 ); // select DAC color palette + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); // registers + + WRITE_S3_UCHAR( DAC_WIndex, 0 ); // start load in register 0 + + for( i = 0, j = 0; i < 256; ++i ) // load all color registers + { + WRITE_S3_UCHAR( DAC_Data, TextPalette[j++] ); // red intensity + WRITE_S3_UCHAR( DAC_Data, TextPalette[j++] ); // green intensity + WRITE_S3_UCHAR( DAC_Data, TextPalette[j++] ); // blue intensity + } + + //========================================================================= + // + // IBMBJB added writes to registers 0x50 - 0x62 to set them to a known + // state because some of them are set by the firmware and are + // not correct for our use + // + // NOTE: there are some writes to the DAC registers in code that + // executes later that depend on R55[1:0] being 00B, if the + // default state of R55 is changed make sure that these bits + // are not changed + + WRITE_S3_UCHAR( S3_3D4_Index, 0x50 ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x51 ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x52 ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x53 ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x54 ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x55 ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x56 ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x57 ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + + WRITE_S3_UCHAR( S3_3D4_Index, 0x58 ); +#ifdef SAM_256 + WRITE_S3_UCHAR( S3_3D5_Data, 0x40 ); +#else + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); +#endif + + WRITE_S3_UCHAR( S3_3D4_Index, 0x59 ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x5a ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x0a ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x5B ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x5C ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x5D ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x5E ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x5F ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + // IBMBJB changed value written from 0 to 1 for an S3 864 based card to + // clear up bad display caused by 864->SDAC FIFO underrun + WRITE_S3_UCHAR( S3_3D4_Index, 0x60 ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x01 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x61 ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x62 ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + //========================================================================= + // + // IBMBJB added setting bits 7 and 6 of CR65, errata sheet fix for split + // transfer problem in parallel and continuous addressing modes + // Note: side effect of setting bit 7 was a garbled firmware screen after + // shutdown. + + // Set SR65 bits 7 and 6 + WRITE_S3_UCHAR(S3_3D4_Index, 0x65); + DataByte = READ_S3_UCHAR(S3_3D5_Data); + DataByte |= 0x40; +// DataByte |= 0xc0; + WRITE_S3_UCHAR(S3_3D5_Data, DataByte); + + // Lock S3 SC registers + WRITE_S3_UCHAR(S3_3D4_Index, S3R9); + WRITE_S3_UCHAR(S3_3D5_Data, 0x0); + + // Lock S3 specific registers + WRITE_S3_UCHAR(S3_3D4_Index, S3R8); + WRITE_S3_UCHAR(S3_3D5_Data, 0x0); + + // Load character fonts into plane 2 (A0000-AFFFF) + WRITE_S3_UCHAR(Seq_Index,0x02); // Enable Write Plane reg + WRITE_S3_UCHAR(Seq_Data,0x04); // select plane 2 + + WRITE_S3_UCHAR(Seq_Index,0x04); // Memory Mode Control reg + WRITE_S3_UCHAR(Seq_Data,0x06); // access to all planes, + + WRITE_S3_UCHAR(GC_Index,0x05); // Graphic, Control Mode reg + WRITE_S3_UCHAR(GC_Data,0x00); + + WRITE_S3_UCHAR(GC_Index,0x06); + WRITE_S3_UCHAR(GC_Data,0x04); + + WRITE_S3_UCHAR(GC_Index,0x04); + WRITE_S3_UCHAR(GC_Data,0x02); + + MemBase = 0xA0000; + for (i = 0; i < 256; i++) { + for (j = 0; j < 16; j++) { + WRITE_S3_VRAM(MemBase, VGAFont8x16[i*16+j]); + MemBase++; + } + // 32 bytes each character font + for (j = 16; j < 32; j++) { + WRITE_S3_VRAM(MemBase, 0 ); + MemBase++; + } + } + + // turn on screen + WRITE_S3_UCHAR(Seq_Index, 0x01); + DataByte = READ_S3_UCHAR(Seq_Data); + DataByte &= 0xdf; + DataByte ^= 0x0; + WRITE_S3_UCHAR(Seq_Data, DataByte); + + WaitForVSync(); + + // Enable all the planes through the DAC + WRITE_S3_UCHAR(DAC_Mask, 0xff); + + // select plane 0, 1 + WRITE_S3_UCHAR(Seq_Index, 0x02); // Enable Write Plane reg + WRITE_S3_UCHAR(Seq_Data, VideoParam[SEQ_OFFSET+0x02]); + + // access to planes 0, 1. + WRITE_S3_UCHAR(Seq_Index, 0x04); // Memory Mode Control reg + WRITE_S3_UCHAR(Seq_Data, VideoParam[SEQ_OFFSET+0x04]); + + WRITE_S3_UCHAR(GC_Index, 0x05); // Graphic, Control Mode reg + WRITE_S3_UCHAR(GC_Data, VideoParam[GRAPH_OFFSET+0x05]); + + WRITE_S3_UCHAR(GC_Index, 0x04); + WRITE_S3_UCHAR(GC_Data, VideoParam[GRAPH_OFFSET+0x04]); + + WRITE_S3_UCHAR(GC_Index, 0x06); + WRITE_S3_UCHAR(GC_Data, VideoParam[GRAPH_OFFSET+0x06]); + + // + // Set screen into blue + // + for (DataLong = 0xB8000; + DataLong < 0xB8000+TWENTY_FIVE_LINES; + DataLong += 2) { + WRITE_S3_VRAM(DataLong, ' '); + WRITE_S3_VRAM(DataLong+1, TEXT_ATTR); + } + // End of initialize S3 standard VGA +3 mode + + // + // Initialize the current display column, row, and ownership values. + // + + HalpColumn = 0; + HalpRow = 0; + HalpDisplayWidth = COLS; + HalpDisplayText = ROWS; + HalpScrollLine = ONE_LINE; + HalpScrollLength = HalpScrollLine * (HalpDisplayText - 1); + HalpDisplayOwnedByHal = TRUE; + + return; +} /* end of HalpDisplayPpcS3Setup() */ + + +VOID +HalDisplayString ( + PUCHAR String + ) + +/*++ + +Routine Description: + + This routine displays a character string on the display screen. + +Arguments: + + String - Supplies a pointer to the characters that are to be displayed. + +Return Value: + + None. + +--*/ + +{ + + KIRQL OldIrql; + + // + // Raise IRQL to the highest level, flush the TB, and map the display + // frame buffer into the address space of the current process. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + // + // If ownership of the display has been switched to the system display + // driver, then reinitialize the display controller and revert ownership + // to the HAL. + // + + + if (HalpDisplayOwnedByHal == FALSE) { + + // + // The display has been put in graphics mode, and we need to + // reset it to text mode before we can display any text on it. + // + + if (HalpResetDisplayParameters) { + HalpDisplayOwnedByHal = HalpResetDisplayParameters(COLS, ROWS); + HalpScreenStart = 0; // used by Cirrus scroll + HalpColumn = 0; + HalpRow = 0; + } + + if (!HalpDisplayOwnedByHal && HalpDisplayControllerSetup != NULL) { + HalpDisplayControllerSetup(); + } + + } + + // + // Display characters until a null byte is encountered. + // + + while (*String != 0) { + HalpDisplayCharacter(*String++); + } + + + // + // Lower IRQL to its previous level. + // + + KeLowerIrql(OldIrql); + + return; +} + +VOID +HalQueryDisplayParameters ( + OUT PULONG WidthInCharacters, + OUT PULONG HeightInLines, + OUT PULONG CursorColumn, + OUT PULONG CursorRow + ) + +/*++ + +Routine Description: + + This routine return information about the display area and current + cursor position. + +Arguments: + + WidthInCharacter - Supplies a pointer to a varible that receives + the width of the display area in characters. + + HeightInLines - Supplies a pointer to a variable that receives the + height of the display area in lines. + + CursorColumn - Supplies a pointer to a variable that receives the + current display column position. + + CursorRow - Supplies a pointer to a variable that receives the + current display row position. + +Return Value: + + None. + +--*/ + +{ + + // + // Set the display parameter values and return. + // + + *WidthInCharacters = HalpDisplayWidth; + *HeightInLines = HalpDisplayText; + *CursorColumn = HalpColumn; + *CursorRow = HalpRow; + return; +} + +VOID +HalSetDisplayParameters ( + IN ULONG CursorColumn, + IN ULONG CursorRow + ) + +/*++ + +Routine Description: + + This routine set the current cursor position on the display area. + +Arguments: + + CursorColumn - Supplies the new display column position. + + CursorRow - Supplies a the new display row position. + +Return Value: + + None. + +--*/ + +{ + + // + // Set the display parameter values and return. + // + + if (CursorColumn > HalpDisplayWidth) { + CursorColumn = HalpDisplayWidth; + } + + if (CursorRow > HalpDisplayText) { + CursorRow = HalpDisplayText; + } + + HalpColumn = CursorColumn; + HalpRow = CursorRow; + return; +} + + +VOID +HalpDisplayCharacterVGA ( + IN UCHAR Character + ) + +/*++ +Routine Description: + + This routine displays a character at the current x and y positions in + the frame buffer. If a newline is encounter, then the frame buffer is + scrolled. If characters extend below the end of line, then they are not + displayed. + +Arguments: + + Character - Supplies a character to be displayed. + +Return Value: + + None. + +--*/ +{ + + // + // If the character is a newline, then scroll the screen up, blank the + // bottom line, and reset the x position. + // + + if (Character == '\n') { + HalpColumn = 0; + if (HalpRow < (HalpDisplayText - 1)) { + HalpRow += 1; + } else { // need to scroll up the screen + HalpScrollScreen(1); + } + } + + //========================================================================= + // + // TAB processing + // + + else if( Character == '\t' ) // tab? + { + HalpColumn += TAB_SIZE; + HalpColumn = (HalpColumn / TAB_SIZE) * TAB_SIZE; + + if( HalpColumn >= COLS ) // tab beyond end of screen? + { + HalpColumn = 0; // next tab stop is 1st column of next line + + if( HalpRow >= (HalpDisplayText - 1) ) + HalpScrollScreen( 1 ); // scroll the screen up + else + ++HalpRow; + } + } + + //========================================================================= + + else if (Character == '\r') { + HalpColumn = 0; + } else if (Character == 0x7f) { /* DEL character */ + if (HalpColumn != 0) { + HalpColumn -= 1; + HalpOutputCharacter(' '); + HalpColumn -= 1; + } else /* do nothing */ + ; + } else if (Character >= 0x20) { + // Auto wrap for 80 columns per line + if (HalpColumn >= COLS) { + HalpColumn = 0; + if (HalpRow < (HalpDisplayText - 1)) { + HalpRow += 1; + } else { // need to scroll up the screen + HalpScrollScreen(1); + } + } + HalpOutputCharacter(Character); + } else /* skip the nonprintable character */ + ; + + return; + +} /* end of HalpDisplayCharacterVGA() */ + + + + +VOID +HalpOutputCharacterS3 ( + IN UCHAR AsciiChar + ) + +/*++ + +Routine Description: + + This routine insert a set of pixels into the display at the current x + cursor position. If the x cursor position is at the end of the line, + then no pixels are inserted in the display. + +Arguments: + + Character - Supplies a character to be displayed. + +Return Value: + + None. + +--*/ + +{ + ULONG I; + + // + // If the current x cursor position is within the current line, then insert + // the specified pixels into the last line of the text area and update the + // x cursor position. + // + if (HalpColumn < COLS) { + I = (HalpRow*HalpScrollLine+HalpColumn*2); + WRITE_S3_VRAM(0xb8000 + I, AsciiChar); + + HalpColumn += 1; + } else // could expand to automatic wrap line. 9/9/92 By Andrew + ; + + return; +} /* end of HalpOutputCharacterS3() */ + + + +VOID +HalpScrollS3(IN UCHAR line) +{ +UCHAR i, DataByte; +ULONG target; + + for (i = 0; i < line; i ++) { + //======================================================================= + // + // wait for vertical sync to make scroll smooth + + WaitForVSync(); + + //======================================================================= + + for (target = 0xB8000; + target < 0xB8000+TWENTY_FOUR_LINES; + target += 2) { + DataByte = READ_S3_VRAM(target+ONE_LINE); + WRITE_S3_VRAM(target, DataByte); + } + for (target = 0xB8000+TWENTY_FOUR_LINES; + target < 0xB8000+TWENTY_FIVE_LINES; + target += 2) { + WRITE_S3_VRAM(target, ' ' ); + } + } +} + +VOID +WaitForVSync (VOID) +{ + UCHAR DataByte; + BOOLEAN test; + + // + // Determine 3Dx or 3Bx + // + + DataByte = READ_S3_UCHAR(MiscOutR); + ColorMonitor = DataByte & 0x01 ? TRUE : FALSE; + + // Unlock S3 ( S3R8 ) + // UnLockS3(); + + // + // Test Chip ID = '81h' ? + // + + // For standard VGA text mode this action is not necessary. + // WRITE_S3_UCHAR(S3_3D4_Index, S3R0); + // if ((DataByte = READ_S3_UCHAR(S3_3D5_Data)) == 0x81) { + // + // Wait For Verttical Retrace + // + + test = TRUE; + while (test) { + READ_S3_UCHAR(Stat1_In); + READ_S3_UCHAR(Stat1_In); + READ_S3_UCHAR(Stat1_In); + + test = READ_S3_UCHAR(Stat1_In) & 0x08 ? FALSE : TRUE; + } + + // Wait for H/V blanking + test = TRUE; + while (test) { + READ_S3_UCHAR(Stat1_In); + READ_S3_UCHAR(Stat1_In); + READ_S3_UCHAR(Stat1_In); + + test = READ_S3_UCHAR(Stat1_In) & 0x01 ? TRUE : FALSE; + } + // } + + // Lock S3 ( S3R8 ) + // LockS3(); + + return; +} /* end of WaitForVsync() */ + +VOID ScreenOn(VOID) +{ + UCHAR DataByte; + + WRITE_S3_UCHAR(Seq_Index, RESET); // Synchronous Reset ! + WRITE_S3_UCHAR(Seq_Data, 0x01); + + WRITE_S3_UCHAR(Seq_Index, CLOCKING_MODE); + DataByte = READ_S3_UCHAR(Seq_Data); + DataByte = DataByte & 0xdf; + WRITE_S3_UCHAR(Seq_Data, DataByte); + + WRITE_S3_UCHAR(Seq_Index, RESET); // reset to normal operation ! + WRITE_S3_UCHAR(Seq_Data, 0x03); + + return; +} + +VOID ScreenOff(VOID) +{ + UCHAR DataByte; + + WRITE_S3_UCHAR(Seq_Index, RESET); // Synchronous Reset ! + WRITE_S3_UCHAR(Seq_Data, 0x01); + + WRITE_S3_UCHAR(Seq_Index, CLOCKING_MODE); + DataByte = READ_S3_UCHAR(Seq_Data); + DataByte = DataByte | 0x20; + WRITE_S3_UCHAR(Seq_Data, DataByte); + + WRITE_S3_UCHAR(Seq_Index, RESET); // reset to normal operation ! + WRITE_S3_UCHAR(Seq_Data, 0x03); + + return; +} + +VOID +HalpDisplayPpcP9Setup ( + VOID + ) +/*++ + +Routine Description: + + This routine initializes the Weitek P9000 display contoller chip. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + PULONG buffer; + ULONG limit, index; + // For now I'll leave the P9000 in the same state that the firmware + // left it in. This should be 640x480. + + HalpHorizontalResolution = 640; + HalpVerticalResolution = 480; + + if (HalpVideoMemoryBase == NULL) { + + HalpVideoMemoryBase = (PUCHAR)KePhase0MapIo(P9_VIDEO_MEMORY_BASE, + 0x400000); // 4 MB + } + + // + // Compute display variables using using HalpFontHeader which is + // initialized in HalpInitializeDisplay(). + // + // N.B. The font information suppled by the OS Loader is used during phase + // 0 initialization. During phase 1 initialization, a pool buffer is + // allocated and the font information is copied from the OS Loader + // heap into pool. + // + //FontHeader = (POEM_FONT_FILE_HEADER)LoaderBlock->OemFontFile; + //HalpFontHeader = FontHeader; + HalpBytesPerRow = (HalpFontHeader->PixelWidth + 7) / 8; + HalpCharacterHeight = HalpFontHeader->PixelHeight; + HalpCharacterWidth = HalpFontHeader->PixelWidth; + + // + // Compute character output display parameters. + // + + HalpDisplayText = + HalpVerticalResolution / HalpCharacterHeight; + + HalpScrollLine = + HalpHorizontalResolution * HalpCharacterHeight; + + HalpScrollLength = HalpScrollLine * (HalpDisplayText - 1); + + HalpDisplayWidth = + HalpHorizontalResolution / HalpCharacterWidth; + + + // + // Set the video memory to address color one. + // + + buffer = (PULONG)HalpVideoMemoryBase; + limit = (HalpHorizontalResolution * + HalpVerticalResolution) / sizeof(ULONG); + + for (index = 0; index < limit; index += 1) { + *buffer++ = 0x01010101; + } + + + // + // Initialize the current display column, row, and ownership values. + // + + HalpColumn = 0; + HalpRow = 0; + HalpDisplayOwnedByHal = TRUE; + return; + +} //end of HalpDisplayPpcP9Setup + +VOID +HalpDisplayCharacterP9 ( + IN UCHAR Character + ) +/*++ + +Routine Description: + + This routine displays a character at the current x and y positions in + the frame buffer. If a newline is encountered, the frame buffer is + scrolled. If characters extend below the end of line, they are not + displayed. + +Arguments: + + Character - Supplies a character to be displayed. + +Return Value: + + None. + +--*/ + +{ + + PUCHAR Destination; + PUCHAR Source; + ULONG Index; + + // + // If the character is a newline, then scroll the screen up, blank the + // bottom line, and reset the x position. + // + if (Character == '\n') { + HalpColumn = 0; + if (HalpRow < (HalpDisplayText - 1)) { + HalpRow += 1; + + } else { + //RtlMoveMemory((PVOID)P9_VIDEO_MEMORY_BASE, + // (PVOID)(P9_VIDEO_MEMORY_BASE + HalpScrollLineP9), + // HalpScrollLengthP9); + + // Scroll up one line + Destination = HalpVideoMemoryBase; + Source = (PUCHAR) HalpVideoMemoryBase + HalpScrollLine; + for (Index = 0; Index < HalpScrollLength; Index++) { + *Destination++ = *Source++; + } + // Blue the bottom line + Destination = HalpVideoMemoryBase + HalpScrollLength; + for (Index = 0; Index < HalpScrollLine; Index += 1) { + *Destination++ = 1; + } + } + + } else if (Character == '\r') { + HalpColumn = 0; + + } else { + if ((Character < HalpFontHeader->FirstCharacter) || + (Character > HalpFontHeader->LastCharacter)) { + Character = HalpFontHeader->DefaultCharacter; + } + + Character -= HalpFontHeader->FirstCharacter; + HalpOutputCharacterP9((PUCHAR)HalpFontHeader + HalpFontHeader->Map[Character].Offset); + } + + return; +} + +VOID +HalpOutputCharacterP9( + IN PUCHAR Glyph + ) + +/*++ + +Routine Description: + + This routine insert a set of pixels into the display at the current x + cursor position. If the current x cursor position is at the end of the + line, then a newline is displayed before the specified character. + +Arguments: + + Character - Supplies a character to be displayed. + +Return Value: + + None. + +--*/ + +{ + + PUCHAR Destination; + ULONG FontValue; + ULONG tmp; + ULONG I; + ULONG J; + + // + // If the current x cursor position is at the end of the line, then + // output a line feed before displaying the character. + // + + if (HalpColumn == HalpDisplayWidth) { + HalpDisplayCharacterP9('\n'); + } + + // + // Output the specified character and update the x cursor position. + // + + Destination = (PUCHAR)(HalpVideoMemoryBase + + (HalpRow * HalpScrollLine) + (HalpColumn * HalpCharacterWidth)); + + for (I = 0; I < HalpCharacterHeight; I += 1) { + FontValue = 0; + for (J = 0; J < HalpBytesPerRow; J += 1) { + FontValue |= *(Glyph + (J * HalpCharacterHeight)) << (24 - (J * 8)); + } + // Move the font bits around so the characters look right. + tmp = (FontValue >> 3) & 0x11111111; //bits 7 and 3 to the right 3 + tmp |= (FontValue >> 1) & 0x22222222; //bits 6 and 2 to the right 1 + tmp |= (FontValue << 1) & 0x44444444; //bits 5 and 1 to the left 1 + tmp |= (FontValue << 3) & 0x88888888; //bits 4 and 0 to the left 3 + FontValue = tmp; + + Glyph += 1; + for (J = 0; J < HalpCharacterWidth ; J += 1) { + if (FontValue >> 31 != 0) + *Destination = 0xFF; //Make this pixel white + + Destination++; + //*Destination++ = (FontValue >> 31) ^ 1; + FontValue <<= 1; + } + + Destination += + (HalpHorizontalResolution - HalpCharacterWidth); + } + + HalpColumn += 1; + return; +} + +VOID +HalpDisplayPpcP91Setup ( + VOID + ) +/*++ + +Routine Description: + + This routine initializes the Weitek P9100 display contoller chip. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + PULONG buffer; + ULONG limit, index; + // For now I'll leave the P9100 in the same state that the firmware + // left it in. This should be 640x480. + + HalpHorizontalResolution = 640; + HalpVerticalResolution = 480; + + if (HalpVideoMemoryBase == NULL) { + + HalpVideoMemoryBase = (PUCHAR)KePhase0MapIo(P91_VIDEO_MEMORY_BASE, + 0x400000); // 4 MB + } + + // + // Compute display variables using using HalpFontHeader which is + // initialized in HalpInitializeDisplay(). + // + // N.B. The font information suppled by the OS Loader is used during phase + // 0 initialization. During phase 1 initialization, a pool buffer is + // allocated and the font information is copied from the OS Loader + // heap into pool. + // + //FontHeader = (POEM_FONT_FILE_HEADER)LoaderBlock->OemFontFile; + //HalpFontHeader = FontHeader; + HalpBytesPerRow = (HalpFontHeader->PixelWidth + 7) / 8; + HalpCharacterHeight = HalpFontHeader->PixelHeight; + HalpCharacterWidth = HalpFontHeader->PixelWidth; + + // + // Compute character output display parameters. + // + + HalpDisplayText = + HalpVerticalResolution / HalpCharacterHeight; + + HalpScrollLine = + HalpHorizontalResolution * HalpCharacterHeight; + + HalpScrollLength = HalpScrollLine * (HalpDisplayText - 1); + + HalpDisplayWidth = + HalpHorizontalResolution / HalpCharacterWidth; + + + // + // Set the video memory to address color one. + // + + buffer = (PULONG)HalpVideoMemoryBase; + limit = (HalpHorizontalResolution * + HalpVerticalResolution) / sizeof(ULONG); + + for (index = 0; index < limit; index += 1) { + *buffer++ = 0x01010101; + } + + + // + // Initialize the current display column, row, and ownership values. + // + + HalpColumn = 0; + HalpRow = 0; + HalpDisplayOwnedByHal = TRUE; + return; + +} //end of HalpDisplayPpcP91Setup + +VOID +HalpDisplayCharacterP91 ( + IN UCHAR Character + ) +/*++ + +Routine Description: + + This routine displays a character at the current x and y positions in + the frame buffer. If a newline is encountered, the frame buffer is + scrolled. If characters extend below the end of line, they are not + displayed. + +Arguments: + + Character - Supplies a character to be displayed. + +Return Value: + + None. + +--*/ + +{ + + PUCHAR Destination; + PUCHAR Source; + ULONG Index; + + // + // If the character is a newline, then scroll the screen up, blank the + // bottom line, and reset the x position. + // + if (Character == '\n') { + HalpColumn = 0; + if (HalpRow < (HalpDisplayText - 1)) { + HalpRow += 1; + + } else { + //RtlMoveMemory((PVOID)P91_VIDEO_MEMORY_BASE, + // (PVOID)(P91_VIDEO_MEMORY_BASE + HalpScrollLineP9), + // HalpScrollLengthP9); + + // Scroll up one line + Destination = HalpVideoMemoryBase; + Source = (PUCHAR) HalpVideoMemoryBase + HalpScrollLine; + for (Index = 0; Index < HalpScrollLength; Index++) { + *Destination++ = *Source++; + } + // Blue the bottom line + Destination = HalpVideoMemoryBase + HalpScrollLength; + for (Index = 0; Index < HalpScrollLine; Index += 1) { + *Destination++ = 1; + } + } + + } else if (Character == '\r') { + HalpColumn = 0; + + } else { + if ((Character < HalpFontHeader->FirstCharacter) || + (Character > HalpFontHeader->LastCharacter)) { + Character = HalpFontHeader->DefaultCharacter; + } + + Character -= HalpFontHeader->FirstCharacter; + HalpOutputCharacterP91((PUCHAR)HalpFontHeader + HalpFontHeader->Map[Character].Offset); + } + + return; +} + +VOID +HalpOutputCharacterP91( + IN PUCHAR Glyph + ) + +/*++ + +Routine Description: + + This routine insert a set of pixels into the display at the current x + cursor position. If the current x cursor position is at the end of the + line, then a newline is displayed before the specified character. + +Arguments: + + Character - Supplies a character to be displayed. + +Return Value: + + None. + +--*/ + +{ + + PUCHAR Destination; + ULONG FontValue; + ULONG tmp; + ULONG I; + ULONG J; + + // + // If the current x cursor position is at the end of the line, then + // output a line feed before displaying the character. + // + + if (HalpColumn == HalpDisplayWidth) { + HalpDisplayCharacterP91('\n'); + } + + // + // Output the specified character and update the x cursor position. + // + + Destination = (PUCHAR)(HalpVideoMemoryBase + + (HalpRow * HalpScrollLine) + (HalpColumn * HalpCharacterWidth)); + + for (I = 0; I < HalpCharacterHeight; I += 1) { + FontValue = 0; + for (J = 0; J < HalpBytesPerRow; J += 1) { + FontValue |= *(Glyph + (J * HalpCharacterHeight)) << (24 - (J * 8)); + } + + Glyph += 1; + for (J = 0; J < HalpCharacterWidth ; J += 1) { + if (FontValue >> 31 != 0) + *Destination = 0xFF; //Make this pixel white + + Destination++; + //*Destination++ = (FontValue >> 31) ^ 1; + FontValue <<= 1; + } + + Destination += + (HalpHorizontalResolution - HalpCharacterWidth); + } + + HalpColumn += 1; + return; +} + + +// +// Cirrus Device Driver +// + +// Routine Description: +// +// This routine displays a character at the current x and y positions in +// the frame buffer. If a newline is encounter, then the frame buffer is +// scrolled. If characters extend below the end of line, then they are not +// displayed. +// +// Arguments: +// +// Character - Supplies a character to be displayed. +// +// Return Value: +// +// None. +// + +VOID +HalpDisplayCharacterCirrus ( + IN UCHAR Character + ) +{ + +// +// If the character is a newline, then scroll the screen up, blank the +// bottom line, and reset the x position. +// + + if (Character == '\n') + { + HalpColumn = 0; + if (HalpRow < (HalpDisplayText - 1)) + { + HalpRow += 1; + } + else + { // need to scroll up the screen + HalpScrollScreen(1); + } + } + +// +// added tab processing +// + + else if ( Character == '\t' ) // tab? + { + HalpColumn += TAB_SIZE; + HalpColumn = (HalpColumn / TAB_SIZE) * TAB_SIZE; + + if ( HalpColumn >= COLS ) // tab beyond end of screen? + { + HalpColumn = 0; // next tab stop is 1st column + // of next line + + if ( HalpRow >= (HalpDisplayText - 1) ) + HalpScrollScreen( 1 ); + else ++HalpRow; + } + } + else if (Character == '\r') + { + HalpColumn = 0; + } + else if (Character == 0x7f) + { // DEL character + if (HalpColumn != 0) + { + HalpColumn -= 1; + HalpOutputCharacterCirrus(' '); + HalpColumn -= 1; + } + else // do nothing + ; + } + else if (Character >= 0x20) + { + // Auto wrap for 80 columns + // per line + if (HalpColumn >= COLS) + { + HalpColumn = 0; + if (HalpRow < (HalpDisplayText - 1)) + { + HalpRow += 1; + } + else + { // need to scroll up the screen + HalpScrollScreen(1); + } + } + HalpOutputCharacterCirrus(Character); + } + // skip the nonprintable character +} + + +// +// +// Routine Description: +// +// This routine insert a set of pixels into the display at the current x +// cursor position. If the x cursor position is at the end of the line, +// then no pixels are inserted in the display. +// +// Arguments: +// +// Character - Supplies a character to be displayed. +// +// Return Value: +// +// None. +// + + +VOID +HalpOutputCharacterCirrus ( + IN UCHAR AsciiChar + ) +{ + PUCHAR Destination; + ULONG I; + +// +// If the current x cursor position is within the current line, then insert +// the specified pixels into the last line of the text area and update the +// x cursor position. +// + + if (HalpColumn < COLS) + { + I = (HalpRow*HalpScrollLine+HalpColumn*2); + Destination = (PUCHAR)(CIRRUS_TEXT_MEM + I + HalpScreenStart); + WRITE_CIRRUS_VRAM(Destination, AsciiChar); + HalpColumn += 1; + } +} + + +// +// Routine Description: +// +// This routine initializes the Cirrus CL-GD5430 graphics controller chip +// + +static void updattr(IN int rg,IN unsigned char val) +{ + inp(0x3da); + outportb(0x3c0,rg); + outportb(0x3c0,val); + outportb(0x3c0,((unsigned char)(rg | 0x20))); +} + + +static void set_ext_regs(IN int reg,IN unsigned char *p) +{ + unsigned char index, data; + + while (*p != 0xff) + { + index= *p++; + data= *p++; + setreg(reg,index,data); + } +} + + +VOID +HalpDisplayPpcCirrusSetup ( + VOID + ) +{ + int i; + + + + if(HalpVideoMemoryBase == NULL) { + HalpVideoMemoryBase = (PUCHAR)KePhase0MapIo(PCI_MEMORY_BASE, + 0x400000); // 4 MB + } + +// +// Assert synchronous reset while setting the clock mode +// + + setreg(0x3c4,0,1); // assert synchronous reset + + outportb(0x3c2,0x67); + + for ( i = 0; i < 21; i++ ) updattr(i,attr3[i]); + + setreg(0x3d4,0x11,0x20); + for ( i = 0; i < 32; i++ ) setreg(0x3d4,i,crtc3[i]); + + for ( i = 0x00;i < 9; i++ ) setreg(0x3ce,i,graph3[i]); + + for ( i = 0; i < 5; i++ ) setreg(0x3c4,i,seq3[i]); + + set_ext_regs (0x3c4,eseq3); + set_ext_regs (0x3d4,ecrtc3); + set_ext_regs (0x3ce,egraph3); + set_ext_regs (0x3c0,eattr3); + +// +// Reset Hidden color register +// + + inp(0x3c6); + inp(0x3c6); + inp(0x3c6); + inp(0x3c6); + outp(0x3c6,0x00); + +// +// Load 8x16 font +// + + load8x16(); + +// +// Load color palette +// + + load_ramdac(); + + outportb(0x3c6,0xff); + +// +// Screen blank +// + + clear_text(); + +// +// Initialize the current display column, row, and ownership values. +// + + HalpColumn = 0; + HalpRow = 0; + HalpDisplayWidth = COLS; + HalpDisplayText = ROWS; + HalpScrollLine = ONE_LINE; + HalpScrollLength = HalpScrollLine * (HalpDisplayText - 1); + HalpDisplayOwnedByHal = TRUE; + HalpScreenStart = 0; +} + +VOID HalpScrollCirrus( + IN UCHAR line + ) +{ ULONG LogicalTarget, PhysicalTarget; + int i; + + for (i=0; i < line; i++) { + + HalpScreenStart = HalpScreenStart + ONE_LINE; + setreg(0x3d4,0xC, (UCHAR) (HalpScreenStart >> 9)); + setreg(0x3d4,0xD, (UCHAR) ((HalpScreenStart >> 1) & 0xFF)); + + for (LogicalTarget = TWENTY_FOUR_LINES; + LogicalTarget < TWENTY_FIVE_LINES; + LogicalTarget += 2) { + PhysicalTarget = LogicalTarget + HalpScreenStart + CIRRUS_TEXT_MEM; + WRITE_CIRRUS_VRAM(PhysicalTarget, ' ' ); + WRITE_CIRRUS_VRAM(PhysicalTarget+1, TEXT_ATTR ); + } + } +} + +static void clear_text(VOID) +{ + unsigned long p; + +// +// fill plane 0 and 1 with 0x20 and 0x1f +// + + for (p = CIRRUS_TEXT_MEM; + p < CIRRUS_TEXT_MEM+TWENTY_FIVE_LINES; + p += 2) + { + WRITE_CIRRUS_VRAM(p, ' '); + WRITE_CIRRUS_VRAM(p+1, TEXT_ATTR); + } +} + +static void load8x16(VOID) +{ + int i, j; + PUCHAR address; + +// +// load 8x16 font into plane 2 +// + + setreg(0x3c4,0x04,(seq3[4] | 0x04)); + +// +// disable video and enable all to cpu to enable maximum video +// memory access +// + + setreg(0x3c4,0x01,seq3[1] | 0x20); + setreg(0x3c4,2,4); + + setreg(0x3ce,0x05,graph3[5] & 0xef); + setreg(0x3ce,0x06,0x05); + + +// +// fill plane 2 with 8x16 font + + address = (void *) (CIRRUS_FONT_MEM); + for ( i = 0; i < 256; i++ ) + { + for ( j = 0; j < 16; j++ ) + { + WRITE_CIRRUS_VRAM(address,VGAFont8x16[i*16+j]); + address++; + } + + for ( j = 16; j < 32; j++ ) + { + WRITE_CIRRUS_VRAM(address,0); + address++; + } + } + + setreg(0x3c4,0x01,seq3[1]); + setreg(0x3c4,0x04,seq3[4]); + setreg(0x3c4,2,seq3[2]); + + setreg(0x3ce,0x06,graph3[6]); + setreg(0x3ce,0x05,graph3[5]); +} + + +static void load_ramdac() +{ + int ix,j; + + for ( ix = 0,j = 0; j <= 0x0FF ; ix = ix+3,j++ ) + { + outp(0x3c8,(unsigned char)j); // write ramdac index + outp(0x3c9,TextPalette[ix]); // write red + outp(0x3c9,TextPalette[ix+1]); // write green + outp(0x3c9,TextPalette[ix+2]); // write blue + } +} + + + + + +VOID HalpOutputCharacterINT10 ( + IN UCHAR Character) +{ ULONG Eax,Ebx,Ecx,Edx,Esi,Edi,Ebp; + + Eax = 2 << 8; // AH = 2 + Ebx = 0; // BH = page number + Edx = (HalpRow << 8) + HalpColumn; + HalCallBios(0x10, &Eax,&Ebx,&Ecx,&Edx,&Esi,&Edi,&Ebp); + + Eax = (0x0A << 8) + Character; // AH = 0xA AL = character + Ebx = 0; + Ecx = 1; + HalCallBios(0x10, &Eax,&Ebx,&Ecx,&Edx,&Esi,&Edi,&Ebp); + + HalpColumn += 1; + +} + + +VOID HalpScrollINT10 ( + IN UCHAR LinesToScroll) + +{ ULONG Eax,Ebx,Ecx,Edx,Esi,Edi,Ebp; + + Eax = 6 << 8; // AH = 6 (scroll up) + Eax |= LinesToScroll; // AL = lines to scroll + Ebx = TEXT_ATTR << 8; // BH = attribute to fill blank line(s) + Ecx = 0; // CH,CL = upper left + Edx = ((ROWS-1) << 8) + COLS - 1; // DH,DL = lower right + HalCallBios(0x10, &Eax,&Ebx,&Ecx,&Edx,&Esi,&Edi,&Ebp); +} + +VOID HalpDisplayINT10Setup (VOID) +{ ULONG Eax,Ebx,Ecx,Edx,Esi,Edi,Ebp; + + HalpColumn = 0; + HalpRow = 0; + HalpDisplayWidth = COLS; + HalpDisplayText = ROWS; + HalpScrollLine = ONE_LINE; + HalpScrollLength = HalpScrollLine * (HalpDisplayText - 1); + + HalpDisplayOwnedByHal = TRUE; + + // + // Reset the display to mode 3 + // + Eax = 0x0003; // Function 0, Mode 3 + Ebx = Ecx = Edx = Esi = Edi = Ebp = 0; + HalCallBios(0x10, &Eax,&Ebx,&Ecx,&Edx,&Esi,&Edi,&Ebp); + + // + // Set cursor to (0,0) + // + Eax = 0x02 << 8; // AH = 2 + Ebx = 0; // BH = page Number + Edx = 0; // DH = row DL = column + HalCallBios(0x10, &Eax,&Ebx,&Ecx,&Edx,&Esi,&Edi,&Ebp); + + // + // Make screen white on blue by scrolling entire screen + // + Eax = 0x06 << 8; // AH = 6 AL = 0 + Ebx = TEXT_ATTR << 8; // BH = attribute + Ecx = 0; // (x,y) upper left + Edx = ((HalpDisplayText-1) << 8); // (x,y) lower right + Edx += HalpScrollLine/2; + HalCallBios(0x10, &Eax,&Ebx,&Ecx,&Edx,&Esi,&Edi,&Ebp); +} + diff --git a/private/ntos/nthals/haleagle/ppc/pxds1385.c b/private/ntos/nthals/haleagle/ppc/pxds1385.c new file mode 100644 index 000000000..b1a48ae12 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxds1385.c @@ -0,0 +1,386 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +contains copyrighted material. Use of this file is restricted +by the provisions of a Motorola Software License Agreement. + +Module Name: + + pxtime.c + +Abstract: + + This module implements the HAL set/query realtime clock routines for + a PowerPC system. + +Author: + + David N. Cutler (davec) 5-May-1991 + +Environment: + + Kernel mode + +Revision History: + + Jim Wooldridge (jimw@austin.vnet.ibm.com) Initial Power PC port + + Change real time clock mapping to port 71. + Code assumes the DS1385S chip is compatible with existing + PC/AT type RTC's. The only known exception to PC/AT + compatibility on S-FOOT is the use of ports 810 and 812. + These ports provide password security for the RTC's NVRAM, + and are currently unused in this port since this address space + is available from kernel mode only in NT. + + Steve Johns (sjohns@pets.sps.mot.com) + Changed to support years > 1999 + +--*/ + +#include "halp.h" +#include "pxds1585.h" +#include "eisa.h" + + +// +// Define forward referenced procedure prototypes. +// + +static UCHAR +HalpReadRawClockRegister ( + UCHAR Register + ); + +static VOID +HalpWriteRawClockRegister ( + UCHAR Register, + UCHAR Value + ); + +static UCHAR +HalpReadClockRegister ( + UCHAR Register + ); + +static VOID +HalpWriteClockRegister ( + UCHAR Register, + UCHAR Value + ); + +BOOLEAN +HalQueryRealTimeClockDs ( + 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 = HalpReadRawClockRegister(RTC_CONTROL_REGISTERD); + if (((PRTC_CONTROL_REGISTER_D)(&DataByte))->ValidTime == 1) { + + // + // Wait until the realtime clock is not being updated. + // + + do { + DataByte = HalpReadRawClockRegister(RTC_CONTROL_REGISTERA); + } while (((PRTC_CONTROL_REGISTER_A)(&DataByte))->UpdateInProgress == 1); + + // + // Read the realtime clock values. + // + + TimeFields->Year = 1900 + (CSHORT)HalpReadClockRegister(RTC_YEAR); + if (TimeFields->Year < 1980) TimeFields->Year += 100; + + TimeFields->Month = (CSHORT)HalpReadClockRegister(RTC_MONTH); + TimeFields->Day = (CSHORT)HalpReadClockRegister(RTC_DAY_OF_MONTH); + TimeFields->Weekday = (CSHORT)HalpReadClockRegister(RTC_DAY_OF_WEEK) - 1; + TimeFields->Hour = (CSHORT)HalpReadClockRegister(RTC_HOUR); + TimeFields->Minute = (CSHORT)HalpReadClockRegister(RTC_MINUTE); + TimeFields->Second = (CSHORT)HalpReadClockRegister(RTC_SECOND); + TimeFields->Milliseconds = 0; + KeLowerIrql(OldIrql); + return TRUE; + + } else { + KeLowerIrql(OldIrql); + return FALSE; + } +} + +BOOLEAN +HalSetRealTimeClockDs ( + 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 = HalpReadRawClockRegister(RTC_CONTROL_REGISTERD); + if (((PRTC_CONTROL_REGISTER_D)(&DataByte))->ValidTime == 1) { + + // + // Set the realtime clock control to set the time. + // + + DataByte = 0; + ((PRTC_CONTROL_REGISTER_B)(&DataByte))->HoursFormat = 1; + + + ((PRTC_CONTROL_REGISTER_B)(&DataByte))->SetTime = 1; + HalpWriteRawClockRegister(RTC_CONTROL_REGISTERB, DataByte); + + // + // Write the realtime clock values. + // + + if (TimeFields->Year > 1999) + HalpWriteClockRegister(RTC_YEAR, (UCHAR)(TimeFields->Year - 2000)); + else + HalpWriteClockRegister(RTC_YEAR, (UCHAR)(TimeFields->Year - 1900)); + + HalpWriteClockRegister(RTC_MONTH, (UCHAR)TimeFields->Month); + HalpWriteClockRegister(RTC_DAY_OF_MONTH, (UCHAR)TimeFields->Day); + HalpWriteClockRegister(RTC_DAY_OF_WEEK, (UCHAR)(TimeFields->Weekday + 1)); + HalpWriteClockRegister(RTC_HOUR, (UCHAR)TimeFields->Hour); + HalpWriteClockRegister(RTC_MINUTE, (UCHAR)TimeFields->Minute); + HalpWriteClockRegister(RTC_SECOND, (UCHAR)TimeFields->Second); + + // + // Set the realtime clock control to update the time. + // + + ((PRTC_CONTROL_REGISTER_B)(&DataByte))->SetTime = 0; + HalpWriteRawClockRegister(RTC_CONTROL_REGISTERB, DataByte); + KeLowerIrql(OldIrql); + return TRUE; + + } else { + KeLowerIrql(OldIrql); + return FALSE; + } +} + +static UCHAR +HalpReadRawClockRegister ( + 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 SIO 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. + // + + // + // TEMPTEMP Disable NMI's for now because this is causing machines in the + // build lab to get NMI's during boot. + // + + + + WRITE_REGISTER_UCHAR(&((PEISA_CONTROL) HalpIoControlBase)->NmiEnable, + Register); + + // + // Read the realtime clock register value. + // + + return READ_REGISTER_UCHAR(&((PRTC_CONTROL)HalpIoControlBase)->RtcData); +} + +static UCHAR +HalpReadClockRegister ( + UCHAR Register + ) + +/*++ + +Routine Description: + + This routine reads the specified realtime clock register. + change return value from BCD to binary integer. I think the chip + can be configured to do this,... but as a quick fix I am doing it + here. (plj) + +Arguments: + + Register - Supplies the number of the register whose value is read. + +Return Value: + + The value of the register is returned as the function value. + +--*/ + +{ + UCHAR BcdValue; + + + BcdValue = HalpReadRawClockRegister(Register); + return (BcdValue >> 4) * 10 + (BcdValue & 0x0f); +} + +static VOID +HalpWriteRawClockRegister ( + 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 SIO NMI enable register. This selects the realtime clock + // register that is written. Note this is a write only register and + // the SIO NMI is always enabled. + // + + + WRITE_REGISTER_UCHAR(&((PEISA_CONTROL) HalpIoControlBase)->NmiEnable, + Register); + + // + // Write the realtime clock register value. + // + + WRITE_REGISTER_UCHAR(&((PRTC_CONTROL)HalpIoControlBase)->RtcData, Value); + return; +} + +static 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. + +--*/ + +{ + UCHAR BcdValue; + + BcdValue = ((Value / 10) << 4) | (Value % 10); + HalpWriteRawClockRegister(Register, BcdValue); + return; +} diff --git a/private/ntos/nthals/haleagle/ppc/pxds1585.h b/private/ntos/nthals/haleagle/ppc/pxds1585.h new file mode 100644 index 000000000..cee3e7fd5 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxds1585.h @@ -0,0 +1,106 @@ + +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + pxds1585.h + +Abstract: + + The module defines the structures, and defines for the DALLAS rtc chip. + +Author: + + Jim Wooldridge + +Revision History: + + +--*/ + + + + +typedef struct _RTC_CONTROL { + UCHAR Reserved0[0x71]; + UCHAR RtcData; // Offset 0x71 +} RTC_CONTROL, *PRTC_CONTROL; + +typedef struct _NVRAM_CONTROL { + UCHAR Reserved0[0x74]; + UCHAR NvramIndexLo; // Offset 0x74 + UCHAR NvramIndexHi; // Offset 0x75 + UCHAR Reserved2[1]; + UCHAR NvramData; // Offset 0x77 +} NVRAM_CONTROL, *PNVRAM_CONTROL; + + +// +// Define Realtime Clock register numbers. +// + +#define RTC_SECOND 0 // second of minute [0..59] +#define RTC_SECOND_ALARM 1 // seconds to alarm +#define RTC_MINUTE 2 // minute of hour [0..59] +#define RTC_MINUTE_ALARM 3 // minutes to alarm +#define RTC_HOUR 4 // hour of day [0..23] +#define RTC_HOUR_ALARM 5 // hours to alarm +#define RTC_DAY_OF_WEEK 6 // day of week [1..7] +#define RTC_DAY_OF_MONTH 7 // day of month [1..31] +#define RTC_MONTH 8 // month of year [1..12] +#define RTC_YEAR 9 // year [00..99] +#define RTC_CONTROL_REGISTERA 10 // control register A +#define RTC_CONTROL_REGISTERB 11 // control register B +#define RTC_CONTROL_REGISTERC 12 // control register C +#define RTC_CONTROL_REGISTERD 13 // control register D +#define RTC_BATTERY_BACKED_UP_RAM 14 // battery backed up RAM [0..49] + +// +// Define Control Register A structure. +// + +typedef struct _RTC_CONTROL_REGISTER_A { + UCHAR RateSelect : 4; + UCHAR TimebaseDivisor : 3; + UCHAR UpdateInProgress : 1; +} RTC_CONTROL_REGISTER_A, *PRTC_CONTROL_REGISTER_A; + +// +// Define Control Register B structure. +// + +typedef struct _RTC_CONTROL_REGISTER_B { + UCHAR DayLightSavingsEnable : 1; + UCHAR HoursFormat : 1; + UCHAR DataMode : 1; + UCHAR SquareWaveEnable : 1; + UCHAR UpdateInterruptEnable : 1; + UCHAR AlarmInterruptEnable : 1; + UCHAR TimerInterruptEnable : 1; + UCHAR SetTime : 1; +} RTC_CONTROL_REGISTER_B, *PRTC_CONTROL_REGISTER_B; + +// +// Define Control Register C structure. +// + +typedef struct _RTC_CONTROL_REGISTER_C { + UCHAR Fill : 4; + UCHAR UpdateInterruptFlag : 1; + UCHAR AlarmInterruptFlag : 1; + UCHAR TimeInterruptFlag : 1; + UCHAR InterruptRequest : 1; +} RTC_CONTROL_REGISTER_C, *PRTC_CONTROL_REGISTER_C; + +// +// Define Control Register D structure. +// + +typedef struct _RTC_CONTROL_REGISTER_D { + UCHAR Fill : 7; + UCHAR ValidTime : 1; +} RTC_CONTROL_REGISTER_D, *PRTC_CONTROL_REGISTER_D; + + diff --git a/private/ntos/nthals/haleagle/ppc/pxenviro.c b/private/ntos/nthals/haleagle/ppc/pxenviro.c new file mode 100644 index 000000000..3248fbbf1 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxenviro.c @@ -0,0 +1,170 @@ +/*++ + +Copyright (c) 1991-1993 Microsoft Corporation + +Module Name: + + pxenviro.c + +Abstract: + + This module implements the interface to the HAL get and set + environment variable routines for a Power PC system. + + +Author: + + Jim Wooldridge Ported to PowerPC + + +Environment: + + Kernel mode + +Revision History: + +--*/ + + +#include "halp.h" +#include "arccodes.h" + +#include "prepnvr.h" +#include "fwstatus.h" +#include "fwnvr.h" + +// This is initialized in pxsystyp during phase 0 init. +NVR_SYSTEM_TYPE nvr_system_type = nvr_systype_unknown; + +KSPIN_LOCK NVRAM_Spinlock; + + + +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. + +--*/ + + +{ + +KIRQL Irql; +PUCHAR tmpbuffer; + + + // + // Check input parameters + // + if (Variable == NULL || + *Variable == 0 || + Length < 1 || + Buffer == NULL) + return(ENOENT); + + // + // Grab control of NVRAM + // + + KeAcquireSpinLock(&NVRAM_Spinlock, &Irql); + + (VOID)nvr_initialize_object(nvr_system_type); + + if ((tmpbuffer = nvr_get_GE_variable(Variable)) == NULL) { + KeReleaseSpinLock(&NVRAM_Spinlock, Irql); + return(ENOENT); + } + + // + // Copy the environment variable's value to Buffer + // + + do { + *Buffer = *tmpbuffer++; + if (*Buffer++ == 0) { + + nvr_delete_object(); + KeReleaseSpinLock(&NVRAM_Spinlock, Irql); + return(ESUCCESS); + } + } while (--Length); + + // + // Truncate the returned string. The buffer was too short. + // + *--Buffer = 0; + + nvr_delete_object(); + KeReleaseSpinLock(&NVRAM_Spinlock, Irql); + return(ENOMEM); +} + +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. + +--*/ + + +{ + ARC_STATUS ReturnValue; + KIRQL Irql; + + + + if (Value == NULL) return(ENOENT); + + KeAcquireSpinLock(&NVRAM_Spinlock, &Irql); // Grab control of NVRAM + + (VOID)nvr_initialize_object(nvr_system_type); + + ReturnValue = nvr_set_GE_variable(Variable,Value); + + nvr_delete_object(); // free object created by nvr_init_object + + KeReleaseSpinLock(&NVRAM_Spinlock, Irql); + + return(ReturnValue); +} diff --git a/private/ntos/nthals/haleagle/ppc/pxflshbf.s b/private/ntos/nthals/haleagle/ppc/pxflshbf.s new file mode 100644 index 000000000..dd7244b39 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxflshbf.s @@ -0,0 +1,186 @@ +// TITLE("Miscellaneous Kernel Functions") +//++ +// +// Copyright (c) 1991 Microsoft Corporation +// +// Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +// contains copyrighted material. Use of this file is restricted +// by the provisions of a Motorola Software License Agreement. +// +// Module Name: +// +// pxflshbf.s +// +// Abstract: +// +// This module implements the system dependent kernel function to flush +// the write buffer or otherwise synchronize writes on a Power PC +// system. +// +// +// +// Author: +// +// David N. Cutler (davec) 24-Apr-1991 +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// +// Jim Wooldridge (jimw@austin.vnet.ibm.com) Initial PowerPC port +// +// Used PowerPC eieio instruction to flush writes +// +//-- + +#include "kxppc.h" + .extern HalpIoControlBase + .set ISA, r.7 + + +// 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) + +// +// It is required that the results of all stores to memory and I/O registers, +// performed in "critical sections" just prior to calling KeFlushWriteBuffer, +// be seen by other processors and mechanisms before returning from this +// routine (KeFlushWriteBuffer). All write-posting queues, both processor and +// external hardware, must be flushed so that their data are seen by other +// processors and controllers on both the PCI and ISA busses. +// + +// +// The Eagle will initiate flushing it's write posting queue on either +// an EIEIO or a SYNC. However, an EIEIO is a NOP on a 603, so we use +// a LOAD from ISA I/O space to get the same effect. +// + + + eieio // + lwz r.4,[toc]HalpIoControlBase(r.toc) + lwz r.4,0(r.4) + lbz r.4, 0x21(r.4) + +// +// Lastly, theFlush write buffers on the processor! To do this, we must use the +// "sync" instruction. The EIEIO instruction does NOT provide the required +// synchronization with external hardware and controllers. +// + + sync + + + LEAF_EXIT(KeFlushWriteBuffer) + + + + LEAF_ENTRY(HalpPatch_KeFlushWriteBuffer) + + mflr r.8 // Save LR + bl Here +Here: mflr r.9 + mtlr r.8 // Restore LR + + addi r.3, r.9, ..HalpFlushWriteBuffer603-Here + addi r.4, r.9, ..HalpFlushWriteBuffer604-Here + + mfpvr r.0 // Distinguish 603/603e from 604/604e + andis. r.0, r.0, 0x0002 + beq PatchTOC + mr r.4, r.3 +PatchTOC: + lwz r.7, [toc]KeFlushWriteBuffer(r.toc) + stw r.4, 0(r.7) + dcbf r.0, r.7 // Flush it from the L1 cache + + LEAF_EXIT(HalpPatch_KeFlushWriteBuffer) + + + LEAF_ENTRY(HalpFlushWriteBuffer603) + lwz r.4,[toc]HalpIoControlBase(r.toc) + lwz r.4,0(r.4) + lbz r.4, 0x21(r.4) + sync + LEAF_EXIT(HalpFlushWriteBuffer603) + + + + LEAF_ENTRY(HalpFlushWriteBuffer604) + eieio // Initiate flushing the Eagle write-post buffers + sync // Wait for the flushing to complete + LEAF_EXIT(HalpFlushWriteBuffer604) + + + +// +//++ +// +// NTSTATUS +// HalpSynchronizeExecution() +// VOID +// ) +// +// Routine Description: +// +// This function flushes the write buffer on the current processor. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpSynchronizeExecution) + + sync // synchronize + + LEAF_EXIT(HalpSynchronizeExecution) + + +// +//++ +// +// VOID +// HalpSetSDR1( +// ULONG HashedPageTableBase, +// ULONG HashedPageTableSize +// ) +// +// HashedPageTableSize is unused because we ASSUME that the HPT is 64K +// + + LEAF_ENTRY(HalpSetSDR1) + + mtsdr1 r.3 + + LEAF_EXIT(HalpSetSDR1) + diff --git a/private/ntos/nthals/haleagle/ppc/pxflshio.c b/private/ntos/nthals/haleagle/ppc/pxflshio.c new file mode 100644 index 000000000..e13615ec9 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxflshio.c @@ -0,0 +1,128 @@ + +/*++ + +Copyright (c) 1991-1993 Microsoft Corporation + Copyright 1994 MOTOROLA, INC. All Rights Reserved. This file + contains copyrighted material. Use of this file is restricted + by the provisions of a Motorola Software License Agreement. + +Module Name: + + psflshio.c + +Abstract: + + This module implements miscellaneous PowerPC HAL functions. + +Author: + + Jim Wooldridge (jimw@austin.ibm.com) + +Environment: + + Kernel mode + +Revision History: + +--*/ + +#include "halp.h" +#include "arccodes.h" + + +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 1; +} + +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. + +--*/ + +{ + + + // + // check for 601, it has a combined I and D cache that bus snoops + // + // + + if ((HalpGetProcessorVersion() >> 16) != 1) { + + // + // If 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. + // + // WARNING: HalSweepDcache is NOT MP-coherent, so calling it like + // this makes this HAL UP-only! + // + + if (((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(); + } + + } + return; +} diff --git a/private/ntos/nthals/haleagle/ppc/pxhalp.h b/private/ntos/nthals/haleagle/ppc/pxhalp.h new file mode 100644 index 000000000..66bbf8e46 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxhalp.h @@ -0,0 +1,253 @@ +/*++ BUILD Version: 0001 // Increment this if a change has global effects + +Copyright (C) 1991-1995 Microsoft Corporation + +Module Name: + + pxhalp.h + +Abstract: + + This header file defines the private Hardware Architecture Layer (HAL) + PowerPC specific interfaces, defines and structures. + + +Author: + + Jeff Havens (jhavens) 20-Jun-91 + +Revision History: + + Jim Wooldridge (jimw@austin.vnet.ibm.com) Initial PowerPC port + + Added externs for HalpInterruptBase,HalpPciConfigBase + Added extern for HalpIoControlBase + Added prototype for HalpHandleDecrementerInterrupt (was in halp.h) + changed adapter object structure to be compatible with the intel HAL + +--*/ + +#ifndef _PXHALP_ +#define _PXHALP_ + + +// +// Define global data used to locate the IO control space, the interrupt +// acknowlege, and the Pci config base. +// + +extern PVOID HalpIoControlBase; +extern PVOID HalpIoMemoryBase; +extern PVOID HalpInterruptBase; +extern PVOID HalpPciConfigBase; +extern PVOID HalpErrorAddressRegister; +extern PVOID HalpPciIsaBridgeConfigBase; + +// +// Define adapter object structure. +// + +// +// The MAXIMUM_MAP_BUFFER_SIZE defines the maximum map buffers which the system +// will allocate for devices which require phyically contigous buffers. +// + +#define MAXIMUM_MAP_BUFFER_SIZE 0x40000 + +// +// Define the initial buffer allocation size for a map buffers for systems with +// no memory which has a physical address greater than MAXIMUM_PHYSICAL_ADDRESS. +// + +#define INITIAL_MAP_BUFFER_SMALL_SIZE 0x10000 + +// +// Define the initial buffer allocation size for a map buffers for systems with +// no memory which has a physical address greater than MAXIMUM_PHYSICAL_ADDRESS. +// + +#define INITIAL_MAP_BUFFER_LARGE_SIZE 0x30000 + +// +// Define the incremental buffer allocation for a map buffers. +// + +#define INCREMENT_MAP_BUFFER_SIZE 0x10000 + +// +// Define the maximum number of map registers that can be requested at one time +// if actual map registers are required for the transfer. +// + +#define MAXIMUM_ISA_MAP_REGISTER 16 + +// +// Define the maximum physical address which can be handled by an Isa card. +// + +#define MAXIMUM_PHYSICAL_ADDRESS 0x01000000 + +// +// Define the scatter/gather flag for the Map Register Base. +// + +#define NO_SCATTER_GATHER 0x00000001 + +// +// Define the copy buffer flag for the index. +// + +#define COPY_BUFFER 0XFFFFFFFF + +// +// 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; + BOOLEAN IsaBusMaster; +} ADAPTER_OBJECT; + +// +// Define function prototypes. +// + +PADAPTER_OBJECT +HalpAllocateIsaAdapter( + IN PDEVICE_DESCRIPTION DeviceDescription, + OUT PULONG NumberOfMapRegisters + ); + +BOOLEAN +HalpCreateSioStructures( + VOID + ); + +VOID +HalpDisableSioInterrupt( + IN ULONG Vector + ); + +BOOLEAN +HalpHandleExternalInterrupt( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext, + IN PVOID TrapFrame + ); + +BOOLEAN +HalpFieldExternalInterrupt( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext, + IN PVOID TrapFrame + ); + +BOOLEAN +HalpHandleDecrementerInterrupt ( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext, + IN PVOID TrapFrame + ); + +VOID +HalpIsaMapTransfer( + IN PADAPTER_OBJECT AdapterObject, + IN ULONG Offset, + IN ULONG Length, + IN BOOLEAN WriteToDevice + ); + +VOID +HalpEnableSioInterrupt( + IN ULONG Vector, + IN KINTERRUPT_MODE InterruptMode + ); + +BOOLEAN +HalpAllocateMapBuffer( + VOID + ); + +ULONG +HalpUpdateDecrementer( + ULONG + ); + +BOOLEAN +HalpPhase0MapBusConfigSpace( + VOID + ); + +VOID +HalpPhase0UnMapBusConfigSpace( + VOID + ); + +ULONG +HalpPhase0GetPciDataByOffset( + ULONG BusNumber, + ULONG SlotNumber, + PVOID Buffer, + ULONG Offset, + ULONG Length + ); + +ULONG +HalpPhase0SetPciDataByOffset( + ULONG BusNumber, + ULONG SlotNumber, + PVOID Buffer, + ULONG Offset, + ULONG Length + ); + +PVOID +KePhase0MapIo( + IN ULONG MemoryBase, + IN ULONG MemorySize + ); + +PVOID +KePhase0DeleteIoMap( + IN ULONG MemoryBase, + IN ULONG MemorySize + ); + +ULONG +HalpCalibrateTB( + VOID + ); + +VOID +HalpZeroPerformanceCounter( + VOID + ); + +VOID +HalpResetIrqlAfterInterrupt( + KIRQL TargetIrql + ); + +#endif // _PXHALP_ diff --git a/private/ntos/nthals/haleagle/ppc/pxhwsup.c b/private/ntos/nthals/haleagle/ppc/pxhwsup.c new file mode 100644 index 000000000..dd0d1ea39 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxhwsup.c @@ -0,0 +1,2199 @@ +/*++ + +Copyright (C) 1990-1995 Microsoft Corporation + +Copyright (C) 1994,1995 MOTOROLA, INC. All Rights Reserved. This file +contains copyrighted material. Use of this file is restricted +by the provisions of a Motorola Software License Agreement. + +Module Name: + + pxhwsup.c + +Abstract: + + This module contains the HalpXxx routines for the NT I/O system that + are hardware dependent. Were these routines not hardware dependent, + they would normally reside in the internal.c module. + +Author: + + Jeff Havens (jhavens) 14-Feb-1990 + +Environment: + + Kernel mode, local to I/O system + +Revision History: + + Jim Wooldridge (jimw@austin.vnet.ibm.com) Initial PowerPC Port + Remove support for internal bus and devices + Changed HalFreeCommonBuffer to support S-FOOT address inversion + Added PCI, PCMCIA, and ISA bus support + Removed support for internal DMA controller + Change HalTranslateBusAddress to support S-FOOTS memory map + Deleted HalpReadEisaBus - this code was specific to EISA buses + Changed IoMapTransfer to support S-FOOT address inversion + Added support for guaranteed contigous common buffers + + + +--*/ + +#include "halp.h" +#include "bugcodes.h" +#include "eisa.h" +#include <pxmemctl.h> + +// +// Put all code for HAL initialization in the INIT section. It will be +// deallocated by memory management when phase 1 initialization is +// completed. +// + + +extern POBJECT_TYPE IoAdapterObjectType; + +// +// Define map buffer variables +// + +PHYSICAL_ADDRESS HalpMapBufferPhysicalAddress; +ULONG HalpMapBufferSize; + + + +// +// The DMA controller has a larger number of map registers which may be used +// by any adapter channel. 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. +// + +PADAPTER_OBJECT MasterAdapterObject; + +VOID +HalpCopyBufferMap( + IN PMDL Mdl, + IN PTRANSLATION_ENTRY TranslationEntry, + IN PVOID CurrentVa, + IN ULONG Length, + IN BOOLEAN WriteToDevice + ); + +BOOLEAN +HalpGrowMapBuffers( + IN PADAPTER_OBJECT AdapterObject, + IN ULONG Amount + ); + + +IO_ALLOCATION_ACTION +HalpAllocationRoutine ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID MapRegisterBase, + IN PVOID Context + ); + + +NTSTATUS +HalAllocateAdapterChannel( + IN PADAPTER_OBJECT AdapterObject, + IN PWAIT_CONTEXT_BLOCK Wcb, + IN ULONG NumberOfMapRegisters, + IN PDRIVER_CONTROL ExecutionRoutine + ) +/*++ + +Routine Description: + + This routine allocates the adapter channel specified by the adapter object. + This is accomplished by placing the device object of the driver that wants + to allocate the adapter on the adapter's queue. If the queue is already + "busy", then the adapter has already been allocated, so the device object + is simply placed onto the queue and waits until the adapter becomes free. + + Once the adapter becomes free (or if it already is), then the driver's + execution routine is invoked. + + Also, a number of map registers may be allocated to the driver by specifying + a non-zero value for NumberOfMapRegisters. Then the map register must be + allocated from the master adapter. Once there are a sufficient number of + map registers available, then the execution routine is called and the + base address of the allocated map registers in the adapter is also passed + to the driver's execution routine. + +Arguments: + + AdapterObject - Pointer to the adapter control object to allocate to the + driver. + + Wcb - Supplies a wait context block for saving the allocation parameters. + The DeviceObject, CurrentIrp and DeviceContext should be initalized. + + NumberOfMapRegisters - The number of map registers that are to be allocated + from the channel, if any. + + ExecutionRoutine - The address of the driver's execution routine that is + invoked once the adapter channel (and possibly map registers) have been + allocated. + +Return Value: + + Returns STATUS_SUCESS unless too many map registers are requested. + +Notes: + + Note that this routine MUST be invoked at DISPATCH_LEVEL or above. + +--*/ +{ + + PADAPTER_OBJECT MasterAdapter; + BOOLEAN Busy = FALSE; + IO_ALLOCATION_ACTION Action; + KIRQL Irql; + ULONG MapRegisterNumber; + + // + // Begin by obtaining a pointer to the master adapter associated with this + // request. + // + + MasterAdapter = AdapterObject->MasterAdapter; + + // + // Initialize the device object's wait context block in case this device + // must wait before being able to allocate the adapter. + // + + Wcb->DeviceRoutine = ExecutionRoutine; + Wcb->NumberOfMapRegisters = NumberOfMapRegisters; + + // + // Allocate the adapter object for this particular device. If the + // adapter cannot be allocated because it has already been allocated + // to another device, then return to the caller now; otherwise, + // continue. + // + + if (!KeInsertDeviceQueue( &AdapterObject->ChannelWaitQueue, + &Wcb->WaitQueueEntry )) { + + // + // Save the parameters in case there are not enough map registers. + // + + AdapterObject->NumberOfMapRegisters = NumberOfMapRegisters; + AdapterObject->CurrentWcb = Wcb; + + // + // The adapter was not busy so it has been allocated. Now check + // to see whether this driver wishes to allocate any map registers. + // Ensure that this adapter has enough total map registers + // to satisfy the request. + // + + if (NumberOfMapRegisters != 0 && AdapterObject->NeedsMapRegisters) { + + // + // Lock the map register bit map and the adapter queue in the + // master adapter object. The channel structure offset is used as + // a hint for the register search. + // + + if (NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel) { + AdapterObject->NumberOfMapRegisters = 0; + IoFreeAdapterChannel(AdapterObject); + return(STATUS_INSUFFICIENT_RESOURCES); + } + + KeAcquireSpinLock( &MasterAdapter->SpinLock, &Irql ); + + MapRegisterNumber = (ULONG)-1; + + if (IsListEmpty( &MasterAdapter->AdapterQueue)) { + + MapRegisterNumber = RtlFindClearBitsAndSet( + MasterAdapter->MapRegisters, + NumberOfMapRegisters, + 0 + ); + } + + if (MapRegisterNumber == (ULONG)-1) { + + // + // There were not enough free map registers. Queue this request + // on the master adapter where is will wait until some registers + // are deallocated. + // + + InsertTailList( &MasterAdapter->AdapterQueue, + &AdapterObject->AdapterQueue + ); + Busy = 1; + + } else { + + // + // Calculate the map register base from the allocated map + // register and base of the master adapter object. + // + + AdapterObject->MapRegisterBase = ((PTRANSLATION_ENTRY) + MasterAdapter->MapRegisterBase + MapRegisterNumber); + + // + // Set the no scatter/gather flag if scatter/gather not + // supported. + // + + if (!AdapterObject->ScatterGather) { + + AdapterObject->MapRegisterBase = (PVOID) + ((ULONG) AdapterObject->MapRegisterBase | NO_SCATTER_GATHER); + + } + } + + KeReleaseSpinLock( &MasterAdapter->SpinLock, Irql ); + + } else { + + AdapterObject->MapRegisterBase = NULL; + AdapterObject->NumberOfMapRegisters = 0; + } + + // + // If there were either enough map registers available or no map + // registers needed to be allocated, invoke the driver's execution + // routine now. + // + + if (!Busy) { + + AdapterObject->CurrentWcb = Wcb; + Action = ExecutionRoutine( Wcb->DeviceObject, + Wcb->CurrentIrp, + AdapterObject->MapRegisterBase, + Wcb->DeviceContext ); + + // + // If the driver would like to have the adapter deallocated, + // then release the adapter object. + // + + if (Action == DeallocateObject) { + + IoFreeAdapterChannel( AdapterObject ); + + } else if (Action == DeallocateObjectKeepRegisters) { + + // + // Set the NumberOfMapRegisters = 0 in the adapter object. + // This will keep IoFreeAdapterChannel from freeing the + // registers. After this it is the driver's responsiblity to + // keep track of the number of map registers. + // + + AdapterObject->NumberOfMapRegisters = 0; + IoFreeAdapterChannel(AdapterObject); + + } + } + } + + return(STATUS_SUCCESS); + +} + +PVOID +HalAllocateCommonBuffer( + IN PADAPTER_OBJECT AdapterObject, + IN ULONG Length, + OUT PPHYSICAL_ADDRESS LogicalAddress, + IN BOOLEAN CacheEnabled + ) +/*++ + +Routine Description: + + This function allocates the memory for a common buffer and maps so that it + can be accessed by a master device and the CPU. + +Arguments: + + AdapterObject - Supplies a pointer to the adapter object used by this + device. + + Length - Supplies the length of the common buffer to be allocated. + + LogicalAddress - Returns the logical address of the common buffer. + + CacheEnable - Indicates whether the memeory is cached or not. + +Return Value: + + Returns the virtual address of the common buffer. If the buffer cannot be + allocated then NULL is returned. + +--*/ + +{ + PVOID virtualAddress; + PHYSICAL_ADDRESS physicalAddress; + + + // + // Allocate the actual buffer. + // + + + physicalAddress.LowPart = 0xFFFFFFFF; + physicalAddress.HighPart = 0; + + virtualAddress = MmAllocateContiguousMemory( + Length, + physicalAddress + ); + + if (virtualAddress == NULL) { + return(NULL); + } + + + + + // + // Memory space inverion + // + + + + *LogicalAddress = MmGetPhysicalAddress(virtualAddress); + + if (!AdapterObject->IsaBusMaster) { + LogicalAddress->LowPart |= IO_CONTROL_PHYSICAL_BASE; + } + + // + // The allocation completed successfully. + // + + return(virtualAddress); + +} + +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. If not all of + the registers could be allocated this field is updated to show how + many were. + +Return Value: + + Returns STATUS_SUCESS if map registers allocated. + +--*/ +{ + PADAPTER_OBJECT MasterAdapter; + ULONG MapRegisterNumber; + + // + // Begin by obtaining a pointer to the master adapter associated with this + // request. + // + + MasterAdapter = AdapterObject->MasterAdapter; + + // + // Check to see whether this driver needs to allocate any map registers. + // + + if (AdapterObject->NeedsMapRegisters) { + + // + // Ensure that this adapter has enough total map registers to satisfy + // the request. + // + + if (*NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel) { + AdapterObject->NumberOfMapRegisters = 0; + return NULL; + } + + // + // Attempt to allocate the required number of map registers w/o + // affecting those registers that were allocated when the system + // crashed. + // + + MapRegisterNumber = (ULONG)-1; + + MapRegisterNumber = RtlFindClearBitsAndSet( + MasterAdapter->MapRegisters, + *NumberOfMapRegisters, + 0 + ); + + if (MapRegisterNumber == (ULONG)-1) { + + // + // Not enough free map registers were found, so they were busy + // being used by the system when it crashed. Force the appropriate + // number to be "allocated" at the base by simply overjamming the + // bits and return the base map register as the start. + // + + RtlSetBits( + MasterAdapter->MapRegisters, + 0, + *NumberOfMapRegisters + ); + MapRegisterNumber = 0; + + } + + // + // Calculate the map register base from the allocated map + // register and base of the master adapter object. + // + + AdapterObject->MapRegisterBase = ((PTRANSLATION_ENTRY) + MasterAdapter->MapRegisterBase + MapRegisterNumber); + + // + // Set the no scatter/gather flag if scatter/gather not + // supported. + // + + if (!AdapterObject->ScatterGather) { + + AdapterObject->MapRegisterBase = (PVOID) + ((ULONG) AdapterObject->MapRegisterBase | NO_SCATTER_GATHER); + + } + + } else { + + AdapterObject->MapRegisterBase = NULL; + AdapterObject->NumberOfMapRegisters = 0; + } + + return AdapterObject->MapRegisterBase; +} + +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 + +--*/ + +{ + + + UNREFERENCED_PARAMETER( AdapterObject ); + UNREFERENCED_PARAMETER( Length ); + UNREFERENCED_PARAMETER( LogicalAddress ); + UNREFERENCED_PARAMETER( CacheEnabled ); + + MmFreeContiguousMemory (VirtualAddress); + + return; + +} +PADAPTER_OBJECT +HalGetAdapter( + IN PDEVICE_DESCRIPTION DeviceDescription, + IN OUT PULONG NumberOfMapRegisters + ) + +/*++ + +Routine Description: + + This function returns the appropriate adapter object for the device defined + in the device description structure. Three bus types are supported for the + system: PCI, Isa. + +Arguments: + + DeviceDescription - 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; + + // + // Make sure this is the correct version. + // + + if (DeviceDescription->Version > DEVICE_DESCRIPTION_VERSION1) { + + return(NULL); + + } + + + // + // If the request is for a unsupported bus then return NULL. + // + + + if (DeviceDescription->InterfaceType != Isa && + DeviceDescription->InterfaceType != PCIBus && + DeviceDescription->InterfaceType != PCMCIABus) { + + // + // This bus type is unsupported return NULL. + // + + return(NULL); + } + + // + // Create an adapter object. + // + + adapterObject = HalpAllocateIsaAdapter( DeviceDescription, + NumberOfMapRegisters); + return(adapterObject); +} + +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 != NULL ) { + + MasterAdapterObject = HalpAllocateAdapter( + MapRegistersPerChannel, + NULL, + 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 == NULL) { + + // + // 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; + AdapterObject->PagePort = NULL; + AdapterObject->IsaBusMaster = FALSE; + + 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 == NULL ) { + + KeInitializeSpinLock( &AdapterObject->SpinLock ); + + InitializeListHead( &AdapterObject->AdapterQueue ); + + AdapterObject->MapRegisters = (PVOID) ( AdapterObject + 1); + + RtlInitializeBitMap( AdapterObject->MapRegisters, + (PULONG) (((PCHAR) (AdapterObject->MapRegisters)) + sizeof( RTL_BITMAP )), + ( MAXIMUM_MAP_BUFFER_SIZE / PAGE_SIZE ) + ); + // + // Set all the bits in the memory to indicate that memory + // has not been allocated for the map buffers + // + + RtlSetAllBits( AdapterObject->MapRegisters ); + AdapterObject->NumberOfMapRegisters = 0; + AdapterObject->CommittedMapRegisters = 0; + + // + // ALlocate the memory map registers. + // + + AdapterObject->MapRegisterBase = ExAllocatePool( + NonPagedPool, + (MAXIMUM_MAP_BUFFER_SIZE / PAGE_SIZE) * + sizeof(TRANSLATION_ENTRY) + ); + + if (AdapterObject->MapRegisterBase == NULL) { + + ObDereferenceObject( AdapterObject ); + AdapterObject = NULL; + return(NULL); + + } + + // + // Zero the map registers. + // + + RtlZeroMemory( + AdapterObject->MapRegisterBase, + (MAXIMUM_MAP_BUFFER_SIZE / PAGE_SIZE) * + sizeof(TRANSLATION_ENTRY) + ); + + if (!HalpGrowMapBuffers(AdapterObject, INITIAL_MAP_BUFFER_SMALL_SIZE)) + { + + // + // If no map registers could be allocated then free the + // object. + // + + ObDereferenceObject( AdapterObject ); + AdapterObject = NULL; + return(NULL); + + } + } + + } else { + + // + // An error was incurred for some reason. Set the return value + // to NULL. + // + + AdapterObject = (PADAPTER_OBJECT) NULL; + } + } else { + + AdapterObject = (PADAPTER_OBJECT) NULL; + + } + + + return AdapterObject; + +} + +VOID +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 ); +} + +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 = ((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; + } + } +} +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. + +--*/ + +{ + + ULONG pageOffset; + ULONG index; + ULONG transferLength; + PULONG pageFrame; + ULONG logicalAddress; + PTRANSLATION_ENTRY translationEntry; + BOOLEAN useBuffer; + PHYSICAL_ADDRESS returnAddress; + + + 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) | IO_CONTROL_PHYSICAL_BASE; + + + while( transferLength < *Length ){ + + if (*pageFrame + 1 != *(pageFrame + 1)) { + break; + } + + transferLength += PAGE_SIZE; + pageFrame++; + + } + + + // + // Limit the transferLength to the requested Length. + // + + transferLength = transferLength > *Length ? *Length : transferLength; + + // + // Determine if the data transfer needs to use the map buffer. + // + + if (MapRegisterBase != NULL) { + + // + // Strip no scatter/gather flag. + // + + translationEntry = (PTRANSLATION_ENTRY) ((ULONG) MapRegisterBase & ~NO_SCATTER_GATHER); + + if ((ULONG) MapRegisterBase & NO_SCATTER_GATHER + && transferLength < *Length) { + + // + // do the memory inversion on the logical address + // + + logicalAddress = ( translationEntry->PhysicalAddress + pageOffset) + | IO_CONTROL_PHYSICAL_BASE; + 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 + ); + } + + // + // ISA masters require memory to be at less than 16 MB. + // always use map buffers for ISA busmasters + // + + if (((logicalAddress+transferLength) & ~IO_CONTROL_PHYSICAL_BASE) + >= MAXIMUM_PHYSICAL_ADDRESS) { + + logicalAddress = (translationEntry + index)->PhysicalAddress + + pageOffset | IO_CONTROL_PHYSICAL_BASE; + + 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 + ); + + } + } + + // + // Return the length. + // + + *Length = transferLength; + + // + // We only support 32 bits, but the return is 64. Just + // zero extend + // + + if (AdapterObject != NULL) { + if (AdapterObject->IsaBusMaster == TRUE) { + returnAddress.LowPart = logicalAddress & ~IO_CONTROL_PHYSICAL_BASE; + } + else { + returnAddress.LowPart = logicalAddress; + } + } + else { + 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) { + + } else { + + + HalpIsaMapTransfer( + AdapterObject, + logicalAddress, + *Length, + WriteToDevice + ); + } + + + 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; + + masterDevice = AdapterObject == NULL || AdapterObject->MasterDevice ? + TRUE : FALSE; + + // + // If this is a slave device, then stop the DMA controller. + // + + if (!masterDevice) { + + // + // Mask the DMA request line so that DMA requests cannot occur. + // + + if (AdapterObject->AdapterNumber == 1) { + + // + // This request is for DMA controller 1 + // + + PDMA1_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_PORT_UCHAR( + &dmaControl->SingleMask, + (UCHAR) (DMA_SETMASK | AdapterObject->ChannelNumber) + ); + + } else { + + // + // This request is for DMA controller 2 + // + + PDMA2_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_PORT_UCHAR( + &dmaControl->SingleMask, + (UCHAR) (DMA_SETMASK | AdapterObject->ChannelNumber) + ); + + } + + } + + if (MapRegisterBase == NULL) { + return(TRUE); + } + + // + // Determine if the data needs to be copied to the orginal buffer. + // This only occurs if the data tranfer is from the device, the + // MapReisterBase is not NULL and the transfer spans a page. + // + + if (!WriteToDevice) { + + // + // Strip no scatter/gather flag. + // + + translationEntry = (PTRANSLATION_ENTRY) ((ULONG) MapRegisterBase & ~NO_SCATTER_GATHER); + + // + // If this is not a master device, then just transfer the buffer. + // + + if ((ULONG) MapRegisterBase & NO_SCATTER_GATHER) { + + if (translationEntry->Index == COPY_BUFFER) { + + if (!masterDevice) { + + // + // Copy only the bytes that have actually been transfered. + // + + Length -= HalReadDmaCounter(AdapterObject); + + } + + // + // The adapter does not support scatter/gather copy the buffer. + // + + HalpCopyBufferMap( + Mdl, + translationEntry, + CurrentVa, + Length, + WriteToDevice + ); + + } + + } 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; + + while( transferLength <= Length ){ + + if (*pageFrame >= BYTES_TO_PAGES(MAXIMUM_PHYSICAL_ADDRESS)) { + + HalpCopyBufferMap( + Mdl, + translationEntry, + CurrentVa, + partialLength, + WriteToDevice + ); + + } + + (PCCHAR) CurrentVa += partialLength; + partialLength = PAGE_SIZE; + + // + // Note that transferLength indicates the amount which will be + // transfered after the next loop; thus, it is updated with the + // new partial length. + // + + transferLength += partialLength; + pageFrame++; + translationEntry++; + } + + // + // Process the any remaining residue. + // + + partialLength = Length - transferLength + partialLength; + + if (partialLength && *pageFrame >= BYTES_TO_PAGES(MAXIMUM_PHYSICAL_ADDRESS)) { + + HalpCopyBufferMap( + Mdl, + translationEntry, + CurrentVa, + partialLength, + WriteToDevice + ); + + } + } + } + + // + // Strip no scatter/gather flag. + // + + translationEntry = (PTRANSLATION_ENTRY) ((ULONG) MapRegisterBase & ~NO_SCATTER_GATHER); + + // + // Clear index in map register. + // + + translationEntry->Index = 0; + + return TRUE; +} + +IO_ALLOCATION_ACTION +HalpAllocationRoutine ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID MapRegisterBase, + IN PVOID Context + ) + +/*++ + +Routine Description: + + This function is called by HalAllocateAdapterChannel when sufficent resources + are available to the driver. This routine saves the MapRegisterBase, + and set the event pointed to by the context parameter. + +Arguments: + + DeviceObject - Supplies a pointer where the map register base should be + stored. + + Irp - Unused. + + MapRegisterBase - Supplied by the Io subsystem for use in IoMapTransfer. + + Context - Supplies a pointer to an event which is set to indicate the + AdapterObject has been allocated. + +Return Value: + + DeallocateObjectKeepRegisters - Indicates the adapter should be freed + and mapregisters should remain allocated after return. + +--*/ + +{ + + UNREFERENCED_PARAMETER(Irp); + + *((PVOID *) DeviceObject) = MapRegisterBase; + + (VOID) KeSetEvent( (PKEVENT) Context, 0L, FALSE ); + + return(DeallocateObjectKeepRegisters); +} + + +BOOLEAN +HalpHandleMachineCheck( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ) +/*++ + +Routine Description: + + This function is called when a PPC Machine Check interrupt occurs. + It print the appropriate status information and bugchecks. + +Arguments: + + Interrupt - Supplies a pointer to the interrupt object + + ServiceContext - Unused + +Return Value: + + Returns TRUE. + +--*/ + +{ + KIRQL OldIrql; + int i; + + // + // raise irql to machine check level + // + + KeRaiseIrql(MACHINE_CHECK_LEVEL,&OldIrql); + + // + // Let the world know what happened. + // + HalDisplayString("\n *** Machine Check Exception ***\n"); + + // + // check memory controller machine check sources + // + + HalpHandleMemoryError(); + + // + // check Bus NMI sources + // + + HalpHandleIoError(); + + // + // Bug check - after stalling to allow + // any information printed on the screen + // by the Memory and IO Handlers to be read. + // + for (i=0; i<12; i++) { + HalDisplayString("."); + KeStallExecutionProcessor(1000000); + } + + KeBugCheck(NMI_HARDWARE_FAILURE); + + KeLowerIrql(OldIrql); + + return(TRUE); +} + + +BOOLEAN +HalpAllocateMapBuffer( + VOID + ) + +/*++ + +Routine Description: + + This routine allocates the required map buffers. + + +Arguments: + + +Return Value: + + TRUE - success + FALSE - failure + +--*/ + +{ + + PVOID virtualAddress; + + // + // Allocate map buffers for the adapter objects + // + + HalpMapBufferSize = INITIAL_MAP_BUFFER_LARGE_SIZE; + + HalpMapBufferPhysicalAddress.LowPart = MAXIMUM_PHYSICAL_ADDRESS; + HalpMapBufferPhysicalAddress.HighPart = 0; + + virtualAddress = MmAllocateContiguousMemory( + HalpMapBufferSize, + HalpMapBufferPhysicalAddress + ); + + if (virtualAddress == NULL) { + + // + // There was not a satisfactory block. Clear the allocation. + // + + HalpMapBufferSize = 0; + return FALSE; + + } + + HalpMapBufferPhysicalAddress = MmGetPhysicalAddress(virtualAddress); + + return TRUE; +} + +VOID +HalpCopyBufferMap( + IN PMDL Mdl, + IN PTRANSLATION_ENTRY TranslationEntry, + IN PVOID CurrentVa, + IN ULONG Length, + IN BOOLEAN WriteToDevice + ) + +/*++ + +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; + + // + // 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, bufferAddress, Length); + + } else { + + RtlMoveMemory(bufferAddress, mapAddress, 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; + PHYSICAL_ADDRESS physicalAddress; + + 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. + // + + 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. + // + + MapBufferVirtualAddress = MmMapIoSpace( + HalpMapBufferPhysicalAddress, + HalpMapBufferSize, + TRUE // Cache enable. + ); + + if (MapBufferVirtualAddress == NULL) { + + // + // The buffer could not be mapped. + // + + HalpMapBufferSize = 0; + + 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) { + + return(FALSE); + } + + // + // Get the physical address of the map base. + // + + MapBufferPhysicalAddress = MmGetPhysicalAddress( + MapBufferVirtualAddress + ).LowPart; + + } + + // + // Initailize the map registers where memory has been allocated. + // + + KeAcquireSpinLock( &AdapterObject->SpinLock, &Irql ); + + TranslationEntry = ((PTRANSLATION_ENTRY) AdapterObject->MapRegisterBase) + + AdapterObject->NumberOfMapRegisters; + + for (i = 0; i < NumberOfPages; i++) { + + // + // Make sure the previous entry is physically contiguous with the next + // entry and that a 64K physical boundary is not crossed unless this + // is an Eisa system. + // + + if (TranslationEntry != AdapterObject->MapRegisterBase && + (((TranslationEntry - 1)->PhysicalAddress + PAGE_SIZE) != + MapBufferPhysicalAddress || + (((TranslationEntry - 1)->PhysicalAddress & ~0x0ffff) != + (MapBufferPhysicalAddress & ~0x0ffff)))) { + + // + // An entry needs to be skipped in the table. This entry will + // remain marked as allocated so that no allocation of map + // registers will cross this boundary. + // + + TranslationEntry++; + AdapterObject->NumberOfMapRegisters++; + } + + // + // Clear the bits where the memory has been allocated. + // + + RtlClearBits( + AdapterObject->MapRegisters, + TranslationEntry - (PTRANSLATION_ENTRY) + AdapterObject->MapRegisterBase, + 1 + ); + + TranslationEntry->VirtualAddress = MapBufferVirtualAddress; + TranslationEntry->PhysicalAddress = MapBufferPhysicalAddress; + TranslationEntry++; + (PCCHAR) MapBufferVirtualAddress += PAGE_SIZE; + MapBufferPhysicalAddress += PAGE_SIZE; + + } + + // + // Remember the number of pages that where allocated. + // + + AdapterObject->NumberOfMapRegisters += NumberOfPages; + + KeReleaseSpinLock( &AdapterObject->SpinLock, Irql ); + return(TRUE); +} diff --git a/private/ntos/nthals/haleagle/ppc/pxidle.c b/private/ntos/nthals/haleagle/ppc/pxidle.c new file mode 100644 index 000000000..038902d85 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxidle.c @@ -0,0 +1,65 @@ +/*++ +TITLE("Processor Idle") + + +Copyright (c) 1994 Microsoft Corporation + +Module Name: + + pxidle.c + +abstract: + + This module implements system platform dependent power management + support. + +Author: + + Jim Wooldridge + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "halp.h" + + + + +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 EE in MSR clear. This routine + must do any power management enabling necessary, set the EE + bit in MSR, then either return or wait for an interrupt. + + Arguments: + + None. + + Return Value: + + None. + + +--*/ + +{ + extern VOID HalpProcessorIdle(VOID); + HalpProcessorIdle(); +} diff --git a/private/ntos/nthals/haleagle/ppc/pxinfo.c b/private/ntos/nthals/haleagle/ppc/pxinfo.c new file mode 100644 index 000000000..0ec6698b9 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxinfo.c @@ -0,0 +1,97 @@ +/*++ + +Copyright (C) 1991-1995 Microsoft Corporation + +Module Name: + + pxinfo.c + +Abstract: + +Environment: + + Kernel mode only. + +--*/ + + +#include "halp.h" + + +NTSTATUS +HalpQueryInstalledBusInformation ( + OUT PVOID Buffer, + IN ULONG BufferLength, + OUT PULONG ReturnedLength + ); + + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE,HaliQuerySystemInformation) +#pragma alloc_text(PAGE,HaliSetSystemInformation) +#endif + + +NTSTATUS +HaliQuerySystemInformation( + IN HAL_QUERY_INFORMATION_CLASS InformationClass, + IN ULONG BufferSize, + OUT PVOID Buffer, + OUT PULONG ReturnedLength + ) +{ + NTSTATUS Status; + PVOID InternalBuffer; + ULONG Length; + union { + HAL_POWER_INFORMATION PowerInf; + HAL_PROCESSOR_SPEED_INFORMATION ProcessorInf; + } U; + + PAGED_CODE(); + + Status = STATUS_SUCCESS; + *ReturnedLength = 0; + Length = 0; + + switch (InformationClass) { + case HalInstalledBusInformation: + Status = HalpQueryInstalledBusInformation ( + Buffer, + BufferSize, + ReturnedLength + ); + break; + + default: + Status = STATUS_INVALID_LEVEL; + break; + } + + // + // If non-zero Length copy data to callers buffer + // + + if (Length) { + if (BufferSize < Length) { + Length = BufferSize; + } + + *ReturnedLength = Length; + RtlCopyMemory (Buffer, InternalBuffer, Length); + } + + return Status; +} + +NTSTATUS +HaliSetSystemInformation ( + IN HAL_SET_INFORMATION_CLASS InformationClass, + IN ULONG BufferSize, + IN PVOID Buffer + ) +{ + PAGED_CODE(); + return STATUS_INVALID_LEVEL; +} diff --git a/private/ntos/nthals/haleagle/ppc/pxinithl.c b/private/ntos/nthals/haleagle/ppc/pxinithl.c new file mode 100644 index 000000000..28233a420 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxinithl.c @@ -0,0 +1,396 @@ +/*++ + +Copyright (c) 1991-1993 Microsoft Corporation + +Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +contains copyrighted material. Use of this file is restricted +by the provisions of a Motorola Software License Agreement. + +Module Name: + + pxinithl.c + +Abstract: + + + This module implements the initialization of the system dependent + functions that define the Hardware Architecture Layer (HAL) for a + Power PC system. + + +Author: + + David N. Cutler (davec) 25-Apr-1991 + +Environment: + + Kernel mode only. + +Revision History: + + Jim Wooldridge (jimw@austin.ibm.com) Initial Power PC port + + Removed call to HalpMapFixedTbEntries, the PPC port + maps all memory via calls to MmMapIoSpace(). + Removed call to HalpInitializeInterrupts - 8259 initialized in phase 1 + Removed Cache error handler - 601 has no cache error interrupt + Removed call to HalpCreateDmaSturctures - it supports internal DMA + +--*/ + +#include "halp.h" +#include "pxmemctl.h" +#include "pxsystyp.h" +extern ADDRESS_USAGE HalpDefaultIoSpace; +extern ULONG HalpPciMaxSlots; +extern ULONG HalpPciConfigSize; + +ULONG +HalpSizeL2Cache( + VOID + ); + +VOID +HalpSynchronizeExecution( + VOID + ); + +VOID +HalpCopyROMs( + VOID + ); + + +VOID HalpPatch_KeFlushWriteBuffer(VOID); + + +// +// Put all code for HAL initialization in the INIT section. It will be +// deallocated by memory management when phase 1 initialization is +// completed. +// + +#if defined(ALLOC_PRAGMA) + +#pragma alloc_text(INIT, HalInitSystem) +#pragma alloc_text(INIT, HalInitializeProcessor) + +#endif + +PVOID HalpIoControlBase = (PVOID) 0; +ULONG L2_Cache_Size; + +VOID +HalpInitBusHandlers ( + VOID + ); + +VOID +HalpRegisterInternalBusHandlers ( + VOID + ); + +VOID +HalpEnableEagleSettings( + VOID + ); + +VOID +HalpCheckHardwareRevisionLevels( + VOID + ); + +VOID +HalpDumpHardwareState( + VOID + ); + +VOID +HalpEnableL2Cache( + VOID + ); + + +// +// Define global spin locks used to synchronize various HAL operations. +// + +KSPIN_LOCK HalpBeepLock; +KSPIN_LOCK HalpDisplayAdapterLock; +KSPIN_LOCK HalpSystemInterruptLock; + +BOOLEAN +HalInitSystem ( + IN ULONG Phase, + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ) + +/*++ + +Routine Description: + + This function initializes the Hardware Architecture Layer (HAL) for a + Power PC 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. + +--*/ + +{ + extern KSPIN_LOCK NVRAM_Spinlock; + PKPRCB Prcb; + + // + // Initialize the HAL components based on the phase of initialization + // and the processor number. + // + + Prcb = PCR->Prcb; + if ((Phase == 0) || (Prcb->Number != 0)) { + + if (Prcb->Number == 0) + HalpSetSystemType( LoaderBlock ); + + // + // Phase 0 initialization. + // + // N.B. Phase 0 initialization is executed on all processors. + // + // + // Get access to I/O space, check if I/O space has already been + // mapped by debbuger initialization. + // + + if (HalpIoControlBase == NULL) { + + HalpIoControlBase = (PVOID)KePhase0MapIo(IO_CONTROL_PHYSICAL_BASE, 0x20000); + + if ( !HalpIoControlBase ) { + return FALSE; + } + } + + + // + // Initialize the display adapter. Must be done early + // so KeBugCheck() will be able to display + // + if (!HalpInitializeDisplay(LoaderBlock)) + return FALSE; + + // Verify that the processor block major version number conform + // to the system that is being loaded. + // + + if (Prcb->MajorVersion != PRCB_MAJOR_VERSION) { + KeBugCheck(MISMATCHED_HAL); + } + + // + // If processor 0 is being initialized, then initialize various + // variables, spin locks, and the display adapter. + // + + if (Prcb->Number == 0) { + + // + // Initialize Spinlock for NVRAM + // + + KeInitializeSpinLock( &NVRAM_Spinlock ); + + // + // Set the interval clock increment value. + // + + HalpCurrentTimeIncrement = MAXIMUM_INCREMENT; + HalpNewTimeIncrement = MAXIMUM_INCREMENT; + KeSetTimeIncrement(MAXIMUM_INCREMENT, MINIMUM_INCREMENT); + + // + // Initialize all spin locks. + // + +#if defined(_MP_PPC_) + + KeInitializeSpinLock(&HalpBeepLock); + KeInitializeSpinLock(&HalpDisplayAdapterLock); + KeInitializeSpinLock(&HalpSystemInterruptLock); + +#endif + + HalpRegisterAddressUsage (&HalpDefaultIoSpace); + + // + // Calibrate execution stall + // + HalpCalibrateStall(); + + // + // Patch KeFlushWriteBuffer to the optimum code sequence + // + HalpPatch_KeFlushWriteBuffer(); + + // + // Size the L2 cache + // + L2_Cache_Size = HalpSizeL2Cache(); + PCR->SecondLevelIcacheSize = L2_Cache_Size << 10; + PCR->SecondLevelDcacheSize = L2_Cache_Size << 10; + + // + // Compute size of PCI Configuration Space mapping + // + HalpPciConfigSize = PAGE_SIZE * ((1 << (HalpPciMaxSlots-2)) + 1); + + // + // Fill in handlers for APIs which this HAL supports + // + + HalQuerySystemInformation = HaliQuerySystemInformation; + HalSetSystemInformation = HaliSetSystemInformation; + HalRegisterBusHandler = HaliRegisterBusHandler; + HalHandlerForBus = HaliHandlerForBus; + HalHandlerForConfigSpace = HaliHandlerForConfigSpace; + + } + + + // + // InitializeInterrupts + // + + if (!HalpInitializeInterrupts()) + return FALSE; + + // + // return success + // + return TRUE; + + + } else { + + if (Phase != 1) + return(FALSE); + + // + // Phase 1 initialization. + // + // N.B. Phase 1 initialization is only executed on processor 0. + // + + + HalpRegisterInternalBusHandlers (); + + + if (!HalpAllocateMapBuffer()) { + return FALSE; + } + + // + // Map I/O space and create ISA data structures. + // + + if (!HalpMapIoSpace()) { + return FALSE; + } + + + if (!HalpCreateSioStructures()) { + return FALSE; + } + + HalpCheckHardwareRevisionLevels(); + HalpEnableL2Cache(); + HalpEnableEagleSettings(); + HalpDumpHardwareState(); + HalpCopyROMs(); + + 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. In order to access the PCR from this + routine, use the PCRsprg1 macro, not the PCR macro. + +Arguments: + + Number - Supplies the number of the processor to initialize. + +Return Value: + + None. + +--*/ + +{ + ULONG IcacheSize, DcacheSize; + ULONG CacheBlockAlignment; + + switch (HalpGetProcessorVersion() >> 16) { + + case 1: // 601 + IcacheSize = 32*1024; + DcacheSize = 32*1024; + CacheBlockAlignment = 32 - 1; + break; + + case 3: // 603 + IcacheSize = 8*1024; + DcacheSize = 8*1024; + CacheBlockAlignment = 32 - 1; + break; + + case 6: // 603e + case 7: // 603ev + case 4: // 604 + IcacheSize = 16*1024; + DcacheSize = 16*1024; + CacheBlockAlignment = 32 - 1; + break; + + case 9: // 604+ + IcacheSize = 32*1024; + DcacheSize = 32*1024; + CacheBlockAlignment = 32 - 1; + break; + + default: + KeBugCheck(HAL_INITIALIZATION_FAILED); + return; + } + + + PCRsprg1->FirstLevelIcacheSize = IcacheSize; + PCRsprg1->FirstLevelDcacheSize = DcacheSize; + PCRsprg1->DcacheAlignment = CacheBlockAlignment; + PCRsprg1->IcacheAlignment = CacheBlockAlignment; + + + return; +} + diff --git a/private/ntos/nthals/haleagle/ppc/pxintsup.s b/private/ntos/nthals/haleagle/ppc/pxintsup.s new file mode 100644 index 000000000..1472ea053 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxintsup.s @@ -0,0 +1,290 @@ +// TITLE("Enable and Disable Processor Interrupts") +//++ +// +// Copyright (c) 1991 Microsoft Corporation +// +// Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +// contains copyrighted material. Use of this file is restricted +// by the provisions of a Motorola Software License Agreement. +// +// Module Name: +// +// pxintsup.s +// +// Abstract: +// +// This module implements the code necessary to mask and unmask +// interrupts on a PowerPC system. +// +// Author: +// +// Steve Johns +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// 30-Dec-93 plj Added 603 support. +// 7-Mar-95 Steve Johns Added HalpUpdate8259 for use in PXIRQL.C +// 13-Mar-95 Steve Johns Assembly version of KeRaiseIrql +// +//-- +#include "halppc.h" + + + + + + + .extern HalpIoControlBase + .extern Halp8259MaskTable + + .set NewIrql, r.3 + .set OldIrql, r.4 + .set Index, r.4 + .set ISA_Base, r.5 + .set MaskTable, r.6 + .set MasterMask, r.8 + .set SlaveMask, r.9 + .set PCR, r.10 + .set MSR, r.11 + .set CLOCK2_LEVEL, 28 + +#define KE_FLUSH_WRITE_BUFFERS() \ + sync ;\ + lbz r.0, 0x21(ISA_Base) + + +// +// VOID HalpUpdate8259(KIRQL NewIrql) +// + + LEAF_ENTRY(HalpUpdate8259) + + + // + // Get pointers to Halp8259MaskTable & ISA I/O space + // + + lwz MaskTable,[toc]Halp8259MaskTable(r.toc) + add Index, NewIrql, NewIrql // Halp8259MaskTable is table of USHORTS + + lwz ISA_Base,[toc]HalpIoControlBase(r.toc) + lwz ISA_Base,0(ISA_Base) + + // + // MasterMask = Halp8259MaskTable[NewIrql]; + // + lhzx MasterMask,Index,MaskTable + + // + // SlaveMask = MasterMask >> 8; + // + srwi SlaveMask, MasterMask, 8 + + // + // WRITE_REGISTER_UCHAR(&(ISA_CONTROL->Interrupt1ControlPort1), + // (UCHAR) MasterMask); + // + stb MasterMask, 0x21(ISA_Base) + + // + // WRITE_REGISTER_UCHAR(&(ISA_CONTROL->Interrupt2ControlPort1), + // (UCHAR) SlaveMask); + // + stb SlaveMask, 0xA1(ISA_Base) + + + // + // Make sure Eagle write buffers are flushed + // + + KE_FLUSH_WRITE_BUFFERS() + + + LEAF_EXIT (HalpUpdate8259) + + +/*************************************************************************/ + +// +// VOID KeRaiseIrql ( KIRQL NewIrql, OUT PKIRQL OldIrql) +// +// Routine Description: +// +// This function raises the current IRQL to the specified value and +// returns the old IRQL value. +// +// Arguments: +// +// NewIrql - Supplies the new IRQL value. +// +// OldIrql - Supplies a pointer to a variable that receives the old +// IRQL value. +// +// NOTE: This assembly routine has been measured to be 25% faster than +// its "C" equivalent. + + LEAF_ENTRY (KeRaiseIrql) + + mfsprg PCR,1 // Get ptr to the PCR + + cmpwi NewIrql, DISPATCH_LEVEL + mfmsr MSR + + // + // *OldIrql = PCR->CurrentIrql; + // + lbz r0,PcCurrentIrql(PCR) + stb r0, 0(OldIrql) + + + // + // If this is a software-to-software transition, + // then don't change hardware interrupt state. + // + // if (NewIrql <= DISPATCH_LEVEL) + // goto RaiseSoftwareToSoftwareIrql; + // + ble RaiseSoftwareToSoftware + + cmpli cr1, 0, NewIrql, CLOCK2_LEVEL + + + // + // MSR[EE] = 0; + // + rlwinm r.0,MSR,0,~MASK_SPR(MSR_EE,1) + mtmsr r.0 + cror 0,0,0 // N.B. 603e/ev Errata 15 + + + // + // if (NewIrql >= CLOCK2_LEVEL) { + // goto RaiseSoftwareToSoftware; + // } + // + + bge 1,RaiseSoftwareToSoftware + + + + + + // + // Get pointers to Halp8259MaskTable & ISA I/O space + // + + lwz MaskTable,[toc]Halp8259MaskTable(r.toc) + add Index, NewIrql, NewIrql // Halp8259MaskTable is table of USHORTS + + lwz ISA_Base,[toc]HalpIoControlBase(r.toc) + lwz ISA_Base,0(ISA_Base) + + // + // MasterMask = Halp8259MaskTable[NewIrql]; + // + lhzx MasterMask,Index,MaskTable + + // + // SlaveMask = MasterMask >> 8; + // + srwi SlaveMask, MasterMask, 8 + + // + // WRITE_REGISTER_UCHAR(&(ISA_CONTROL->Interrupt1ControlPort1), + // (UCHAR) MasterMask); + // + stb MasterMask, 0x21(ISA_Base) + + + // + // WRITE_REGISTER_UCHAR(&(ISA_CONTROL->Interrupt2ControlPort1), + // (UCHAR) SlaveMask); + // + stb SlaveMask, 0xA1(ISA_Base) + + + // + // Make sure Eagle write buffers are flushed. + // + + KE_FLUSH_WRITE_BUFFERS() + + // + // PCR->CurrentIrql = NewIrql; + // + stb NewIrql, PcCurrentIrql(PCR) + + + // + // MSR[EE] = 1; + // + ori MSR,MSR,MASK_SPR(MSR_EE,1) + mtmsr MSR + cror 0,0,0 // N.B. 603e/ev Errata 15 + + blr + + + +RaiseSoftwareToSoftware: + // + // PCR->CurrentIrql = NewIrql; + // + stb NewIrql, PcCurrentIrql(PCR) + + LEAF_EXIT (KeRaiseIrql) + + + +// +// VOID HalpResetIrqlAfterInterrupt(KIRQL NewIrql) +// +// Routine Description: +// +// This function disables external interrupts, lowers the current +// IRQL to the specified value and returns with interrupts disabled. +// +// This routine is called instead of KeLowerIrql to return IRQL to +// its level prior to being raised due to an external interrupt. +// +// We know current IRQL is > DISPATCH_LEVEL +// +// Arguments: +// +// NewIrql - Supplies the new IRQL value. +// +// Return Value: +// +// None. +// + +// { +// HalpDisableInterrupts(); +// PCR->CurrentIrql = NewIrql; +// if (NewIrql < CLOCK2_LEVEL) +// HalpUpdate8259(NewIrql); +// } + + + LEAF_ENTRY (HalpResetIrqlAfterInterrupt) + + mfmsr MSR + cmpwi NewIrql, CLOCK2_LEVEL + mfsprg PCR,1 // Get ptr to the PCR + + // + // MSR[EE] = 0; + // + rlwinm MSR,MSR,0,~MASK_SPR(MSR_EE,1) + mtmsr MSR + cror 0,0,0 // N.B. 603e/ev Errata 15 + + + stb NewIrql,PcCurrentIrql(PCR) + blt+ ..HalpUpdate8259 + + LEAF_EXIT (HalpResetIrqlAfterInterrupt) + diff --git a/private/ntos/nthals/haleagle/ppc/pxirql.c b/private/ntos/nthals/haleagle/ppc/pxirql.c new file mode 100644 index 000000000..2fecf0219 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxirql.c @@ -0,0 +1,261 @@ +// TITLE("Manipulate Interrupt Request Level") +//++ +// +// Copyright (c) 1990 Microsoft Corporation +// Copyright 1994 MOTOROLA, INC. All Rights Reserved. This file +// contains copyrighted material. Use of this file is restricted +// by the provisions of a Motorola Software License Agreement. +// +// Module Name: +// +// PXIRQL.C +// +// Abstract: +// +// This module implements the code necessary to lower and raise the current +// Interrupt Request Level (IRQL). +// +// +// Author: +// +// Jim Wooldridge (IBM) +// Steve Johns (Motorola) +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// 22-Feb-94 Steve Johns (Motorola) +// KeRaiseIrql - Disabled interrupts at PIC if IRQL >= DEVICE_LEVEL +// KeLowerIrql - Enabled interrupts at PIC if IRQL < DEVICE_LEVEL +// 15-Apr-94 Jim Wooldridge +// Added irql interrupt mask table and expanded irql range from (0-8) +// to (0-31). +// +//-- + +#include "halp.h" + +// +// Initialize the 8259 IRQL mask table +// + +USHORT Halp8259MaskTable[] = { 0x0000, // irql0 Low level + 0x0000, // irql1 APC + 0x0000, // irql2 Dispatch + 0x0000, // irql3 + 0x0000, // irql4 + 0x0000, // irql5 + 0x0000, // irql6 + 0x0000, // irql7 + 0x0000, // irql8 + 0x0000, // irql9 + 0x0000, // irql10 + 0x0080, // irql11 parallel + 0x00C0, // irql12 floppy + 0x00E0, // irql13 parallel + 0x00F0, // irql14 com 1 + 0x00F8, // irql15 com 2 + 0x80F8, // irql16 pci slot + 0xC0F8, // irql17 isa slot + 0xE0F8, // irql18 scsi + 0xF0F8, // irql19 mouse + 0xF8F8, // irql20 isa slot + 0xFCF8, // irql21 audio + 0xFEF8, // irql22 isa slot + 0xFFF8, // irql23 rtc + 0xFFF8, // irql24 cascade + 0xFFFA, // irql25 kb + 0xFFFB, // irql26 timer 1 + 0xFFFB, // irql27 PROFILE_LEVEL + 0xFFFF, // irql28 CLOCK LEVEL + 0xFFFF, // irql29 IPI_LEVEL + 0xFFFF, // irql30 POWER_LEVEL + 0xFFFF // irql31 HIGH_LEVEL + }; + + + +VOID +KiDispatchSoftwareInterrupt( + VOID + ); + +VOID +HalpUpdate8259( + KIRQL NewIrql + ); + + +// +// VOID +// KeLowerIrql ( +// KIRQL NewIrql +// ) +// +// Routine Description: +// +// This function lowers the current IRQL to the specified value. +// +// Arguments: +// +// NewIrql - Supplies the new IRQL value. +// +// Return Value: +// +// None. +// +//-- + + +VOID +KeLowerIrql( + KIRQL NewIrql + ) + +{ KIRQL OldIrql; + + + OldIrql = PCR->CurrentIrql; + + // + // If this is a software-to-software transition don't change hardware + // interrupt state + // + + if (OldIrql > DISPATCH_LEVEL) { + + HalpDisableInterrupts(); + PCR->CurrentIrql = NewIrql; + + // + // If old IRQL is < CLOCK2_LEVEL then interrupt are enabled + // in the MSR but the 8259 mask must be updated. If not, then + // interrupts need to be enabled, however the 8259 does not need to + // be updated. + // + + if (NewIrql < CLOCK2_LEVEL) { + HalpUpdate8259(NewIrql); + HalpEnableInterrupts(); + } + } else { + PCR->CurrentIrql = NewIrql; + } + + // + // check for DPC's + + if ((NewIrql < DISPATCH_LEVEL) && PCR->SoftwareInterrupt) + KiDispatchSoftwareInterrupt(); + +} + +#if 0 // This code has been re-written in assembly. See PXINTSUP.C +// +// VOID +// HalpResetIrqlAfterInterrupt( +// KIRQL TargetIrql +// ) +// +// Routine Description: +// +// This function disables external interrupts, lowers the current +// IRQL to the specified value and returns with interrupts disabled. +// +// This routine is called instead of KeLowerIrql to return IRQL to +// its level prior to being raised due to an external interrupt. +// +// We know current IRQL is > DISPATCH_LEVEL +// +// Arguments: +// +// TargetIrql - Supplies the new IRQL value. +// +// Return Value: +// +// None. +// +//-- + + +VOID +HalpResetIrqlAfterInterrupt( + KIRQL TargetIrql + ) + +{ + + PUCHAR PIC_Address; + USHORT PIC_Mask; + + + HalpDisableInterrupts(); + PCR->CurrentIrql = TargetIrql; + + // + // If TargetIrql < CLOCK2_LEVEL, then the 8259 mask must be updated. + // + + if (TargetIrql < CLOCK2_LEVEL) { + HalpUpdate8259(TargetIrql); + } +} + +/*************************************************************************/ + +// +// VOID KeRaiseIrql ( +// KIRQL NewIrql, +// PKIRQL OldIrql +// ) +// +// Routine Description: +// +// This function raises the current IRQL to the specified value and returns +// the old IRQL value. +// +// Arguments: +// +// NewIrql - Supplies the new IRQL value. +// +// OldIrql - Supplies a pointer to a variable that receives the old +// IRQL value. +// + +VOID +KeRaiseIrql( + IN KIRQL NewIrql, + OUT PKIRQL OldIrql + ) + +{ + // + // If this is a software-to-software transition, don't change hardware + // interrupt state + // + + if (NewIrql > DISPATCH_LEVEL) { + + HalpDisableInterrupts(); + *OldIrql = PCR->CurrentIrql; + PCR->CurrentIrql = NewIrql; + + // + // If new IRQL is >= CLOCK2_LEVEL, disable interrupts in the MSR but + // don't touch the 8259's. Otherwise, leave interrupts enabled and + // update the 8259's. + // + + if (NewIrql < CLOCK2_LEVEL) { + HalpUpdate8259(NewIrql); + HalpEnableInterrupts(); + } + + } else { + *OldIrql = PCR->CurrentIrql; + PCR->CurrentIrql = NewIrql; + } +} +#endif diff --git a/private/ntos/nthals/haleagle/ppc/pxisabus.c b/private/ntos/nthals/haleagle/ppc/pxisabus.c new file mode 100644 index 000000000..0c0c03faf --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxisabus.c @@ -0,0 +1,130 @@ +/*++ + + +Copyright (C) 1989-1995 Microsoft Corporation + +Module Name: + + pxisabus.c + +Abstract: + +Author: + +Environment: + +Revision History: + + +--*/ + +#include "halp.h" + +ULONG +HalpGetIsaInterruptVector( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ); + + +NTSTATUS +HalpAdjustIsaResourceList ( + IN PVOID BusHandler, + IN PVOID RootHandler, + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList + ); + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE,HalpGetIsaInterruptVector) +#pragma alloc_text(PAGE,HalpAdjustIsaResourceList) +#endif + + +ULONG +HalpGetIsaInterruptVector( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ) + +/*++ + +Routine Description: + + This function returns the system interrupt vector and IRQL level + corresponding to the specified bus interrupt level and/or vector. The + system interrupt vector and IRQL are suitable for use in a subsequent call + to KeInitializeInterrupt. + +Arguments: + + BusHandle - Per bus specific structure + + Irql - Returns the system request priority. + + Affinity - Returns the system wide irq affinity. + +Return Value: + + Returns the system interrupt vector corresponding to the specified device. + +--*/ +{ + + // + // irq2 shows up on irq9 + // + + if (BusInterruptLevel == 2) { + BusInterruptLevel = 9; + BusInterruptVector = 9; + } + + if (BusInterruptLevel > 15) { + return 0; + } + + // + // Get parent's translation from here.. + // + return BusHandler->ParentHandler->GetInterruptVector ( + BusHandler->ParentHandler, + RootHandler, + BusInterruptLevel, + BusInterruptVector, + Irql, + Affinity + ); +} + + + +NTSTATUS +HalpAdjustIsaResourceList ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList + ) +{ + + SUPPORTED_RANGE InterruptRange; + + RtlZeroMemory (&InterruptRange, sizeof InterruptRange); + InterruptRange.Base = 0; + InterruptRange.Limit = 15; + + return HaliAdjustResourceListRange ( + BusHandler->BusAddresses, + &InterruptRange, + pResourceList + ); +} + diff --git a/private/ntos/nthals/haleagle/ppc/pxl2.s b/private/ntos/nthals/haleagle/ppc/pxl2.s new file mode 100644 index 000000000..045e29257 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxl2.s @@ -0,0 +1,551 @@ +// +// +// Copyright (c) 1993 IBM Corporation +// +// Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +// contains copyrighted material. Use of this file is restricted +// by the provisions of a Motorola Software License Agreement. +// +// Module Name: +// +// PXL2.S +// +// Abstract: +// +// This module implements the routines to size & enable the L2 cache +// on an Eagle based system. +// +// Author: +// +// Steve Johns (sjohns@pets.sps.mot.com) +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// 11-Aug-94 saj Added Eagle L2 cache support for Big Bend. +// 23-Nov-94 saj Added input parameter specifying write-back or write-thru +// 01-Dec-94 saj Removed all hardware workarounds +// Enable L2 Parity error checking (Eagle register 0xC4) +// 08-Mar-95 saj Added input parameter EagleAC +// 21-Aug-95 v-matth Steve's sizing functionality is walking on the +// page file database if we have 128Mb of RAM. I'm +// going to change it to save off main memory before +// we do our writes to main memory, then restore those +// values before we exit. +// 01-Sep-95 saj Check if L2 is already enabled. If so, just exit. +// Otherwise, size L2 and exit with L2 disabled. Don't read +// DBATs, since can't be read reliably on 603e. +// + +#include "kxppc.h" +#include "halppc.h" + + .extern HalpIoControlBase + + .set HID0, 1008 +// +// Eagle register A8 fields: +// + .set CF_WRITE_THRU, 0x0001 // Write-through + .set CF_WRITE_BACK, 0x0002 // Write-back + .set CF_L2_MP, 0x0003 // Bits 1..0 (LE bit order) + +// +// Eagle register AC fields: +// + .set L2_EN, 0x40000000 + .set L2_UPDATE_EN, 0x80000000 + .set CF_FLUSH_L2, 0x10000000 + .set CF_INV_MODE, 0x00001000 +// +// L2 cache sizes: +// + .set CF_L2_SIZE, 0x0030 // Bits 5..4 (LE bit order) + .set L2_1M, 0x0020 + .set L2_512K, 0x0010 + .set L2_256K, 0x0000 + .set L2_LINE_SIZE, 32 +// +// Local parameters +// + .set CacheSize, r.3 // Return value + .set Pattern, r.3 + .set Offset, r.5 + .set EagleA8, r.6 + .set EagleAC, r.7 + .set L2off, r.8 // Eagle register A8 for L2 disabled + .set Restore, r.9 + .set ISA, r.10 // Pointer to ISA I/O space + .set Virtual, r.11 + + .set Pattern0, 0x77777777 // Patterns for L2 cache sizing + .set Pattern1, 0x11111111 + .set Pattern2, 0x22222222 + .set Pattern3, 0X33333333 + .set Pattern4, 0x44444444 + + .set VIRTUAL, 0xFFC00000 // Virtual address for L2 sizing + .set PHYSICAL, 0x00C00000 // Physical mem. used for L2 sizing + .set BAT_REG, 1 // BAT register to use for L2 sizing + +//*********************************************************************** +// +// Synopsis: +// ULONG HalpSizeL2(VOID) +// +// Purpose: +// Sizes and enables the Eagle L2 cache. +// +// Returns: +// Size of L2 cache or zero if not installed. +// Valid sizes are 256, 512, and 1024. +// +// Global Variables Referenced: +// HalpIoControlBase +// +// NOTE: Interrupts are assumed to be disabled upon entry. +//*********************************************************************** + + + LEAF_ENTRY(HalpSizeL2) + +// +// Lock the I-cache so instruction fetching doesn't impact the L2 cache +// while we are sizing it. With the I-cache locked, instruction fetches will +// not bursted in, so the L2 will not respond to those cycles. +// + mfspr r.0, HID0 + ori r.0, r.0, 0x2000 // Lock the Icache + mtspr HID0, r.0 + + + +// +// Get ptr to Eagle I/O (ISA bus) +// + lwz ISA,[toc]HalpIoControlBase(r.toc) // Get base of ISA I/O + lwz ISA,0(ISA) + + LWI (EagleA8, 0x800000A8) // Processor Interface Configuration 1 + addi EagleAC, EagleA8, 4 // Processor Interface Configuration 2 + +// +// Return if L2 cache is already enabled. +// + stw EagleAC, 0xCF8(ISA) + sync + lwz r.0, 0xCFC(ISA) + andis. r.4, r.0, (L2_EN >> 16) // Test L2_EN + beq Init_BAT + + stw EagleA8, 0xCF8(ISA) + sync + lwz r.4, 0xCFC(ISA) + andi. r.4, r.4, CF_L2_MP // Test CF_L2_MP + beq Init_BAT + + andi. r.0, r.0, CF_L2_SIZE // Isolate L2 size field + cmpi 0,0,r.0, 0x30 // Reserved ? + li CacheSize, 0 + beq L2_Exit + + li CacheSize, 256 + cmpi 0,0,r.0, L2_256K + beq L2_Exit + + li CacheSize, 512 + cmpi 0,0,r.0, L2_512K + beq L2_Exit + + li CacheSize, 1024 + b L2_Exit + + +// +// Initialize a BAT register to map the memory at PHYSICAL to VIRTUAL. +// The sizing algorithm depends on the block of memory being marked WRITE-THRU. +// +Init_BAT: + LWI (Virtual, VIRTUAL) + LWI (r.0, PHYSICAL + 0x5A) // WIMG = 1011; PP = 10 + mtdbatl BAT_REG, r.0 + ori r.0, Virtual, 0x003F // BL = 2MB; Vs = Vp = 1 + mtdbatu BAT_REG, r.0 + + isync + + + +// +// Save the 4 test locations. +// + lis Offset, 4 // Offset = 256K + + lwz Pattern,[toc].LRDATA(rtoc) // Pattern <- address of .LRDATA + lwz r.0, 0 (Virtual) + stw r.0, 0 (Pattern) // Save Memory[ 0K]; + dcbf r.0, Virtual + + lwzux r.0, Virtual, Offset + dcbf r.0, Virtual + stw r0, 4(Pattern) // Save Memory[256K]; + + lwzux r.0, Virtual, Offset + mr r.9, Virtual // r.9 = Virtual + 512K + dcbf r.0, Virtual + stw r0, 8(Pattern) // Save Memory[512K]; + + lwzux r.0, Virtual, Offset + dcbf r.0, Virtual + stw r0,12(Pattern) // Save Memory[768K]; + LWI (Virtual, VIRTUAL) + + +// +// Set the L2 cache to Write-Through +// + stw EagleA8, 0xCF8(ISA) + sync + lwz L2off, 0xCFC(ISA) + rlwinm L2off, L2off,0,~CF_L2_MP + ori r.0, L2off, CF_WRITE_THRU + stw r.0, 0xCFC(ISA) + sync + +// +// Enable the L2 cache for 1 MB +// + stw EagleAC, 0xCF8(ISA) + sync + lwz r.0, 0xCFC(ISA) + rlwinm r.0, r.0, 0, ~CF_L2_SIZE + ori r.0, r.0, L2_1M + oris r.0, r.0, ((L2_EN+L2_UPDATE_EN) >> 16) + stw r.0, 0xCFC(ISA) + sync + sync + +// +// Load the 4 test locations into the L2 cache. +// + lwzx r.0, r.9, Offset // 768 KB + lwz r.0, 0(r.9) // 512 KB + lwzx r.0, Virtual, Offset // 256 KB + lwz r.0, 0 (Virtual) // 0 KB + + +// +// Store different patterns to the 4 test locations. This should cause +// values to be stored in the L2 cache and memory. +// + LWI (Pattern, Pattern4) // L2_Cache[768K] = Pattern4; + stwx Pattern, r.9, Offset + + LWI (Pattern, Pattern3) // L2_Cache[512K] = Pattern3; + stw Pattern, 0 (r.9) + + LWI (Pattern, Pattern2) // L2_Cache[256K] = Pattern2; + stwx Pattern, Virtual, Offset + + LWI (Pattern, Pattern1) // L2_Cache[ 0K] = Pattern1; + stw Pattern, 0 (Virtual) + +// +// Disable the L2 cache. The tags are NOT invalidated. No L2 snoop +// operations or data updates are performed. +// + stw EagleAC, 0xCF8(ISA) + sync + lwz r.0, 0xCFC(ISA) + rlwinm r.0, r.0, 0, ~(L2_EN+L2_UPDATE_EN) + stw r.0, 0xCFC(ISA) + sync + +// +// Store PATTERN0 to our 4 test locations. Only L1 and main memory will be +// written since the L2 cache has been disabled. This allows us to distinguish +// patterns in the L2 from main memory. +// + + LWI (Pattern, Pattern0) // L2_Cache[768K] = Pattern0; + stwx Pattern, r.9, Offset + stw Pattern, 0 (r.9) // L2_Cache[512K] = Pattern0; + stwx Pattern, Virtual,Offset // L2_Cache[256K] = Pattern0; + stw Pattern, 0 (Virtual) // L2_Cache[ 0K] = Pattern0; + +// +// Load 8 locations (for an 8-way L1 cache) 4096 bytes apart in order to flush +// the test locations from the L1. We can't use DCBF since that would flush +// the L2 also. +// + lwzu Pattern, 4096(Virtual) + lwzu Pattern, 4096(Virtual) + lwzu Pattern, 4096(Virtual) + lwzu Pattern, 4096(Virtual) + lwzu Pattern, 4096(Virtual) + lwzu Pattern, 4096(Virtual) + lwzu Pattern, 4096(Virtual) + lwzu Pattern, 4096(Virtual) + LWI (Virtual, VIRTUAL) + +// +// Re-enable the L2 cache +// + stw EagleAC, 0xCF8(ISA) + sync + lwz r.0, 0xCFC(ISA) + oris r.0, r.0, ((L2_EN + L2_UPDATE_EN) >> 16) + stw r.0, 0xCFC(ISA) + sync + + lwz Pattern, 0(Virtual) // Read test location @ 0 KB + lwzx r.0, Virtual, Offset // Read test location @ 256 KB + rlwimi Pattern, r.0, 0, 8, 15 + lwz r.0, 0 (r.9) // Read test location @ 512 KB + rlwimi Pattern, r.0, 0, 16, 23 + lwzx r.0, r.9, Offset // Read test location @ 768 KB + rlwimi Pattern, r.0, 0, 24, 31 + +// +// Test the pattern from L2 to determine it's size +// + + LWI (r.0, 0x11777777) + cmpl 0,0, Pattern, r.0 + beq Set_256K + + LWI (r.0, 0x11227777) + cmpl 0,0, Pattern, r.0 + beq Set_512K + + LWI (r.0, 0x11223344) + cmpl 0,0, Pattern, r.0 + beq Set_1M + +// LWI (r.0, 0x77777777) +// cmpl 0,0, Pattern, r.0 +// bne InvalidPattern + + li CacheSize, 0 + b DisableCache + + +// +// Unexpected pattern. Return it for display. +// +InvalidPattern: +// mr CacheSize, Pattern // Not needed if CacheSize == Pattern + b DisableCache + + + +Set_256K: + li CacheSize, 256 + li r.4, L2_256K + b SetCacheSize + +Set_512K: + li CacheSize, 512 + li r.4, L2_512K + b SetCacheSize + +Set_1M: + li CacheSize, 1024 + li r.4, L2_1M + +// +// r.3 = cache size in KB +// r.4 = cache size field to be inserted into Eagle register AC. +// +SetCacheSize: + stw EagleAC, 0xCF8(ISA) + sync + lwz r.9, 0xCFC(ISA) + rlwimi r.9, r.4, 0, CF_L2_SIZE // Insert CF_L2_SIZE field + stw r.9, 0xCFC(ISA) + sync + +// +// Eagle 2.1 BUG: +// Write-back works OK +// Write-thru walks thru addresses but does not invalidate them. +// Don't need to flush for write-thru anyway!!!! +// +// NOTE: If changing from WRITE-BACK to WRITE-THROUGH, you must flush +// beforehand because castouts are not supported in write-through. +// If the L2 has dirty data, then switching to write-through, the +// dirty data won't get flushed (cast out) to main memory. +// + rlwinm r.4, r.9, 0, 1,31 // Clear L2_UPDATE_EN (lock L2) + stw r.4, 0xCFC(ISA) + oris r.0, r.4, (CF_FLUSH_L2 >> 16) // Toggle CF_FLUSH_L2 + sync + stw r.0, 0xCFC(ISA) + sync + stw r.4, 0xCFC(ISA) +// +// Flush the L2 by walking through memory (2x L2 size) +// + rlwinm r.0, CacheSize, 10-5+1, 0, 31 // L2Size * (1024 / LINE_SIZE) * 2 + mtctr r.0 + subi r.4, Virtual, L2_LINE_SIZE +FlushLoop: + lwzu r.0, L2_LINE_SIZE (r.4) + bdnz FlushLoop + +// +// Disable the L2 cache +// +DisableCache: + sync + lwz r.9, 0xCFC(ISA) + rlwinm r.9, r.9, 0, ~(L2_EN+L2_UPDATE_EN) + stw r.9, 0xCFC(ISA) + sync + + + stw EagleA8, 0xCF8(ISA) + sync + stw L2off, 0xCFC(ISA) // Disable the L2 cache + sync + +// +// Restore the original contents of the test locations +// + lwz Restore,[toc].LRDATA(rtoc) + lwz r0, 0(Restore) // Restore test location 0 + stw r0, 0(Virtual) + + lwz r0, 4(Restore) // Restore test location 1 + stwux r0, Virtual, Offset + + lwz r0, 8(Restore) // Restore test location 2 + stwux r0, Virtual, Offset + + lwz r0,12(Restore) // Restore test location 3 + stwx r0, Virtual, Offset + + li r.0, 0 // Invalidate the BAT we used + mtdbatu BAT_REG, r.0 + mtdbatl BAT_REG, r.0 +L2_Exit: + mfspr r.0, HID0 + rlwinm r.0, r.0, 0, ~0x2000 // Unlock the Icache + mtspr HID0, r.0 + + LEAF_EXIT(HalpSizeL2) + + + + +//*********************************************************************** +// +// Synopsis: +// VOID HalpFlushAndDisableL2(VOID) +// +// Purpose: +// If the L2 is enabled and in WRITE-BACK mode, the L2 is flushed. +// In either mode, the L2 is invalidated, and upon exit, the L2 is +// left disabled. +// +// Returns: +// nothing +// +// Global Variables Referenced: +// HalpIoControlBase +// +// NOTE: Interrupts are assumed to be disabled upon entry. +//*********************************************************************** + LEAF_ENTRY(HalpFlushAndDisableL2) + + mfsprg r.12, 1 // Get PCR->SecondLevelDcacheSize + lwz r.0, PcSecondLevelDcacheSize (r.12) + srwi. r.0, r.0, 5 // # lines in L2 + beqlr- + mtctr r.0 + + + lwz ISA,[toc]HalpIoControlBase(r.toc) // Get base of ISA I/O + lwz ISA,0(ISA) + + LWI (EagleA8, 0x800000A8) // Processor Interface Configuration 1 + addi EagleAC, EagleA8, 4 // Processor Interface Configuration 2 + + stw EagleAC, 0xCF8(ISA) + sync + lwz r.5, 0xCFC(ISA) + andis. r.0, r.5, (L2_EN >> 16) // Disable the L2 (L2_EN = 0) + beqlr + + mfspr r.9, HID0 // Lock the Icache + ori r.0, r.9, 0x2000 + mtspr HID0, r.0 + isync + + stw EagleA8, 0xCF8(ISA) // Check CF_L2_MP + sync + lwz r.4, 0xCFC(ISA) + andi. r.0, r.4, CF_L2_MP + beq FlushExit // Return if L2 is disabled + + + cmpwi r.0, CF_WRITE_THRU // Is L2 in write-through mode ? + beq InvalidateL2 // Yes, then flush is not necessary + +// +// Flush the L2 contents to main memory +// + stw EagleAC, 0xCF8(ISA) // Clear L2_UPDATE_EN (lock L2) + rlwinm r.0, r.5, 0, 1,31 + oris r.0, r.0, (CF_FLUSH_L2 >> 16) // Toggle CF_FLUSH_L2 + stw r.0, 0xCFC(ISA) + sync + stw r.5, 0xCFC(ISA) + + +InvalidateL2: + stw EagleAC, 0xCF8(ISA) // Clear L2_UPDATE_EN (lock L2) + sync + rlwinm r.5, r.5, 0, 2,0 // Clear L2_EN (disable the L2 cache) + ori r.0, r.5, CF_INV_MODE // Set L2 to invalidate mode + stw r.0, 0xCFC(ISA) + sync + +// +// Invalidate the L2 by walking thru memory +// + LWI (r.12, 0x80000000-L2_LINE_SIZE) +Invalidate: + lwzu r.0, L2_LINE_SIZE (r.12)// Read from L2 cache + bdnz Invalidate + + + stw EagleA8, 0xCF8(ISA) + sync + rlwinm r.4, r.4, 0, ~CF_L2_MP // Clear CF_L2_MP + stw r.4, 0xCFC(ISA) + +FlushExit: + stw EagleAC, 0xCF8(ISA) + sync + rlwinm r.5, r.5, 0, 2,31 // Clear L2_EN & L2_UPDATE_EN + stw r.5, 0xCFC(ISA) // Clear CF_INV_MODE + + + mtspr HID0, r.9 // Unlock the Icache + + LEAF_EXIT(HalpFlushAndDisableL2) + + +.LRDATA: +// loc 0 - Holds memory at 0K + .ualong 0x0 +// loc 4 - Holds memory at 256K + .ualong 0x0 +// loc 8 - Holds memory at 512K + .ualong 0x0 +// loc 12 - Holds memory at 1024K + .ualong 0x0 + diff --git a/private/ntos/nthals/haleagle/ppc/pxmapio.c b/private/ntos/nthals/haleagle/ppc/pxmapio.c new file mode 100644 index 000000000..edf50cc91 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxmapio.c @@ -0,0 +1,124 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +contains copyrighted material. Use of this file is restricted +by the provisions of a Motorola Software License Agreement. + +Module Name: + + pxmapio.c + +Abstract: + + This module implements the mapping of HAL I/O space for a POWER PC + system. + +Author: + + David N. Cutler (davec) 28-Apr-1991 + +Environment: + + Kernel mode + +Revision History: + + Jim Wooldridge (jimw@austin.vnet.ibm.com) Initial PowerPC port + + Map interrupt acknowledge base address + Map SIO config base address + Remove RTC map - S-FOOT mapsthe RTC into the ISA I/O space + +--*/ + +#include "halp.h" + +// +// Put all code for HAL initialization in the INIT section. It will be +// deallocated by memory management when phase 1 initialization is +// completed. +// + +#if defined(ALLOC_PRAGMA) + +#pragma alloc_text(INIT, HalpMapIoSpace) + +#endif + + +BOOLEAN +HalpMapIoControlSpace ( + VOID + ); + +BOOLEAN +HalpMapPlanarSpace ( + VOID + ); + +BOOLEAN +HalpMapBusConfigSpace ( + VOID + ); + +// +// Define global data used to locate the IO control space and the PCI config +// space. +// + +PVOID HalpInterruptBase; +PVOID HalpPciConfigBase; +PVOID HalpErrorAddressRegister; + + +BOOLEAN +HalpMapIoSpace ( + VOID + ) + +/*++ + +Routine Description: + + This routine maps the HAL I/O, planar control, and bus configuration + spaces for a PowerPC 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. + +--*/ + +{ + + // + // Map bus/bridge I/O control space + // + + if (!HalpMapIoControlSpace()) + return FALSE; + + // + // Map Planar I/O control space + // + + if (!HalpMapPlanarSpace()) + return FALSE; + + // + // Map Bus configuration space + // + + if (!HalpMapBusConfigSpace()) + return FALSE; + + + return TRUE; +} diff --git a/private/ntos/nthals/haleagle/ppc/pxmemctl.c b/private/ntos/nthals/haleagle/ppc/pxmemctl.c new file mode 100644 index 000000000..9a844710b --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxmemctl.c @@ -0,0 +1,1643 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +contains copyrighted material. Use of this file is restricted +by the provisions of a Motorola Software License Agreement. + +Module Name: + + pxmemctl.c + +Abstract: + + The module initializes any planar registers. + This module also implements machince check parity error handling. + +Author: + + Jim Wooldridge (jimw@austin.vnet.ibm.com) + Steve Johns (sjohns@pets.sps.mot.com) + +Revision History: + +--*/ + + + +#include "halp.h" +#include "pxmemctl.h" +#include "pxpcisup.h" +#include "pci.h" +#include "pcip.h" +#include "arccodes.h" +#include "pxsystyp.h" +#include <string.h> + + +ULONG PciInterruptRoutingOther = 15; + +VOID HalDisplayString(PUCHAR String); +ULONG HalpGetHID0(VOID); +VOID HalpSetHID0(ULONG Value); +BOOLEAN HalpStrCmp(); +VOID HalpEnableL2Cache(VOID); +ULONG HalpSizeL2Cache(VOID); +extern ULONG HalpSizeL2(VOID); +extern ULONG L2_Cache_Size; +extern VOID HalpFlushAndDisableL2(VOID); +extern HalpPciConfigSize; +BOOLEAN HalpInitPlanar(VOID); +BOOLEAN HalpMapPlanarSpace(VOID); +VOID HalpEnableEagleSettings(VOID); +VOID HalpEnable_HID0_Settings(ULONG); +VOID HalpCheckHardwareRevisionLevels(VOID); +VOID HalpDumpHardwareState(VOID); + +#define EAGLECHIPID 0x0001 + +#define BUF_LEN 120 +#define NEGATECHAR '~' + +#define EagleIndexRegister ((PULONG) (((PUCHAR) HalpIoControlBase) + 0xcf8)) +#define EagleDataRegister ((((PUCHAR) HalpIoControlBase) + 0xcfc)) + +#define HalpReadEagleUlong(Port) \ + (*EagleIndexRegister = (Port), __builtin_eieio(), *((PULONG) EagleDataRegister)) + +#define HalpWriteEagleUlong(Port, Value) \ + (*EagleIndexRegister = (Port), *((PULONG) EagleDataRegister) = (Value), __builtin_sync()) + +#define HalpReadEagleUshort(Port) \ + (*EagleIndexRegister = (Port&~3), __builtin_eieio(), *((PUSHORT)(EagleDataRegister+(Port&0x2)))) + +#define HalpWriteEagleUshort(Port, Value) \ + (*EagleIndexRegister = (Port&~3), *((PUSHORT)(EagleDataRegister+(Port&0x2))) = (Value), __builtin_sync()) + +#define HalpWriteEagleUchar(Port, Value) \ + (*EagleIndexRegister = (Port&~3), *((PUCHAR)(EagleDataRegister+(Port&0x3))) = (Value), __builtin_sync()) + + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT,HalpStrCmp) +#pragma alloc_text(INIT,HalpEnableL2Cache) +#pragma alloc_text(INIT,HalpInitPlanar) +#pragma alloc_text(INIT,HalpMapPlanarSpace) +#pragma alloc_text(INIT,HalpEnableEagleSettings) +#pragma alloc_text(INIT,HalpEnable_HID0_Settings) +#pragma alloc_text(INIT,HalpCheckHardwareRevisionLevels) +#pragma alloc_text(INIT,HalpSizeL2Cache) +#endif + + +UCHAR HalpReadEagleUchar(ULONG Port) +{ UCHAR c; + *EagleIndexRegister = Port & ~3; + __builtin_eieio(); + c = *((PUCHAR)(EagleDataRegister+(Port&0x3))); + return (c); +} + + +// Eagle rev 2.1 reads Config register 0xC0 bit 4 into bit 3 instead. +// Writes to bit 4 are OK. +UCHAR HalpReadEagleC0(ULONG Port) +{ UCHAR c; + + c = HalpReadEagleUchar(0x800000C0); + c |= ((c & 0x08) << 1); + return (c); +} + + + +typedef UCHAR (*PHALP_READ_EAGLE) (ULONG Port); +PHALP_READ_EAGLE HalpReadEagleRegC0; + + +#define HalpDisplayHex32(Num, Buf) HalpDisplayHex( 32, Num, Buf) +#define HalpDisplayHex16(Num, Buf) HalpDisplayHex( 16, Num, Buf) +#define HalpDisplayHex8(Num, Buf) HalpDisplayHex( 8, Num, Buf) + +VOID HalpDisplayHex( + ULONG NoBits, + ULONG Number, + IN PUCHAR Buffer +) +{ int Bits; + + for (Bits=NoBits-4; Bits >= 0; Bits -=4) { + *Buffer++ = (UCHAR) ((((Number >> Bits) & 0xF) > 9) ? + ((Number >> Bits) & 0xF) - 10 + 'A' : + ((Number >> Bits) & 0xF) + '0'); + } + *Buffer++ = '.'; + *Buffer++ = '\n'; + *Buffer++ = '\0'; + +} + + +UCHAR HalpUpperCase(UCHAR c) +{ + if (c >= 'a' && c <= 'z') + c -= 'a'-'A'; + return c; +} + + +// +// Routine Description: +// +// This routine is a helper routine for parameter parsing. It compares +// String1 to String2. +// +// Return Value +// +// TRUE if strings match; otherwise FALSE +// MatchLen - the number of characters correctly matched. +// + +// #define HalpStrCmp(String1, String2) ( strcmp(String1, String2) == 0) +BOOLEAN HalpStrCmp( char *String0, char *String1 ) +{ +char *tmp0, *tmp1; + + tmp0 = String0; + tmp1 = String1; + while( (*tmp0 = toupper( *tmp0 )) && (*tmp1 = toupper( *tmp1 )) ) + { + tmp0++; tmp1++; + } + return( strcmp(String0, String1) == 0 ); +} + +typedef struct tagEAGLEA8 { + union { + struct { + ULONG CF_L2_MP : 2; + ULONG SPECULATIVE_PCI : 1; + ULONG CF_APARK : 1; + ULONG CF_LOOP_SNOOP : 1; + ULONG LITTLE_ENDIAN : 1; + ULONG STORE_GATHERING : 1; + ULONG NO_PORTS_REG : 1; + ULONG Reserved1 : 1; + ULONG CF_DPARK : 1; + ULONG TEA_EN : 1; + ULONG MCP_EN : 1; + ULONG FLASH_WR_EN : 1; + ULONG CF_LBA_EN : 1; + ULONG Reserved2 : 1; + ULONG CF_MP_ID : 1; + ULONG ADDRESS_MAP : 1; + ULONG PROC_TYPE : 2; + ULONG DISCONTIGOUS_IO : 1; + ULONG ROM_CS : 1; + ULONG CF_CACHE_1G : 1; + ULONG CF_BREAD_WS : 2; + ULONG CF_CBA_MASK : 8; + } EagleA8; + + ULONG AsUlong; + } u; +} EAGLEA8; + +typedef struct tagEAGLEAC { + union { + struct { + ULONG CF_WDATA : 1; + ULONG CF_DOE : 1; + ULONG CF_APHASE : 2; + ULONG CF_L2_SIZE : 2; + ULONG CF_TOE_WIDTH : 1; + ULONG CF_FAST_CASTOUT : 1; + ULONG CF_BURST_RATE : 1; + ULONG CF_L2_HIT_DELAY : 2; + ULONG reserved1 : 1; + ULONG CF_INV_MODE : 1; + ULONG CF_HOLD : 1; + ULONG CF_ADDR_ONLY : 1; + ULONG reserved2 : 1; + ULONG CF_HIT_HIGH : 1; + ULONG CF_MOD_HIGH : 1; + ULONG CF_SNOOP_WS : 2; + ULONG CF_WMODE : 2; + ULONG CF_DATA_RAM_TYP : 2; + ULONG CF_FAST_L2_MODE : 1; + ULONG CF_BYTE_DECODE : 1; + ULONG reserved3 : 2; + ULONG CF_FLUSH_L2 : 1; + ULONG reserved4 : 1; + ULONG L2_ENABLE : 1; + ULONG L2_UPDATE_EN : 1; + } EagleAC; + + ULONG AsUlong; + } u; +} EAGLEAC; + + + +typedef struct tagEAGLEC0 { + union { + struct { + UCHAR LOCAL_BUS : 1; + UCHAR PCI_MASTER_ABORT : 1; + UCHAR MEM_READ_PARITY : 1; + UCHAR Reserved : 1; + UCHAR MASTER_PERR : 1; + UCHAR MEM_SELECT_ERROR : 1; + UCHAR SLAVE_PERR : 1; + UCHAR PCI_TARGET_ABORT : 1; + } EagleC0; + + UCHAR AsUchar; + } u; +} EAGLEC0; + + +typedef enum { + MPC601 = 1, + MPC603 = 3, + MPC603e = 6, + MPC604 = 4, + MPC604e = 9 +} CPU_TYPE; + + +// Parity Enable for memory interface +#define PCKEN 0x10000 +// Machine Check Enable +#define MCP_EN 0x800 +// Memory Read Parity Enable +#define MRPE 0x04 + +typedef enum { + WriteThrough, + WriteBack +} L2MODE; + +// Oem Output Display function filter noise if OEM or quite + +VOID OemDisplayString(PUCHAR String) +{ +UCHAR CharBuffer[BUF_LEN]; + + if(HalGetEnvironmentVariable("HALREPORT",sizeof(CharBuffer),&CharBuffer[0]) == ESUCCESS) { + if(HalpStrCmp("YES", CharBuffer)) { + HalDisplayString(String); + } + } else { + if(HalGetEnvironmentVariable("MOT-OEM-ID",sizeof(CharBuffer),&CharBuffer[0]) != ESUCCESS) { + HalDisplayString(String); + } + } +} + +char * +MyStrtok ( + char * string, + const char * control + ) +{ + unsigned char *str; + const unsigned char *ctrl = control; + + unsigned char map[32]; + int count; + + static char *nextoken; + + /* Clear control map */ + for (count = 0; count < 32; count++) + map[count] = 0; + + /* Set bits in delimiter table */ + do { + map[*ctrl >> 3] |= (1 << (*ctrl & 7)); + } while (*ctrl++); + + /* Initialize str. If string is NULL, set str to the saved + * pointer (i.e., continue breaking tokens out of the string + * from the last strtok call) */ + if (string) + str = string; + else + str = nextoken; + + /* Find beginning of token (skip over leading delimiters). Note that + * there is no token iff this loop sets str to point to the terminal + * null (*str == '\0') */ + while ( (map[*str >> 3] & (1 << (*str & 7))) && *str ) + str++; + + string = str; + + /* Find the end of the token. If it is not the end of the string, + * put a null there. */ + for ( ; *str ; str++ ) + if ( map[*str >> 3] & (1 << (*str & 7)) ) { + *str++ = '\0'; + break; + } + + /* Update nextoken (or the corresponding field in the per-thread data + * structure */ + nextoken = str; + + /* Determine if a token has been found. */ + if ( string == str ) + return NULL; + else + return string; +} + + +VOID HalpEnableL2Cache() +{ EAGLEAC EagleRegAC; + EAGLEA8 EagleRegA8; + USHORT CpuRevision; + CPU_TYPE CpuType; + BOOLEAN SynchronousSRAMs, Negate; + UCHAR EagleRevision; + L2MODE Mode; + int i; + UCHAR CharBuffer[BUF_LEN], *Value, c1, c2; + UCHAR L2_Parameter[BUF_LEN]; + + long BridgeChipId; + + BridgeChipId = HalpReadEagleUshort(0x80000002); + + // + // For non-EAGLE chips, firmware has already enabled the L2 cache. + // No further action is necessary, return. + // + if (BridgeChipId != EAGLECHIPID) + return; + + EagleRevision = HalpReadEagleUchar(0x80000008); + + // + // Set some fields in Eagle Register 0xA8 + // + EagleRegA8.u.AsUlong = HalpReadEagleUlong(0x800000A8); + EagleRegA8.u.EagleA8.TEA_EN = 1; // Enable TEA + + CpuRevision = (USHORT)(HalpGetProcessorVersion() & 0xFFFF); + CpuType = (CPU_TYPE)(HalpGetProcessorVersion() >> 16); + + EagleRegA8.u.EagleA8.CF_BREAD_WS = 0; // works for 601 & 604 + switch (CpuType) { + case MPC601: + EagleRegA8.u.EagleA8.PROC_TYPE = 0; + break; + + case MPC603: + case MPC603e: + EagleRegA8.u.EagleA8.PROC_TYPE = 2; + EagleRegA8.u.EagleA8.CF_BREAD_WS = 1; // assumes DRTRY mode !!! + break; + + case MPC604: + case MPC604e: + EagleRegA8.u.EagleA8.PROC_TYPE = 3; + break; + } + + // + // Set the default L2 cache timing. + // The timing will be platform dependent. + // If the L2 is already on (via firmware), just return. + // + + EagleRegAC.u.AsUlong = HalpReadEagleUlong(0x800000AC); + if (EagleRegAC.u.EagleAC.L2_ENABLE) + return; + + EagleRegAC.u.EagleAC.CF_WMODE = 3; + EagleRegAC.u.EagleAC.CF_MOD_HIGH = 1; + EagleRegAC.u.EagleAC.CF_ADDR_ONLY = 1; + EagleRegAC.u.EagleAC.CF_APHASE = 1; + EagleRegAC.u.EagleAC.CF_DOE = 1; + EagleRegAC.u.EagleAC.CF_WDATA = 1; + EagleRegAC.u.EagleAC.L2_UPDATE_EN = 1; + EagleRegAC.u.EagleAC.L2_ENABLE = 1; + + + switch (HalpSystemType) { + case MOTOROLA_BIG_BEND: + case MOTOROLA_POWERSTACK: + default: + SynchronousSRAMs = TRUE; + break; + } + + if (SynchronousSRAMs) { + EagleRegAC.u.EagleAC.CF_DATA_RAM_TYP = 0; + EagleRegAC.u.EagleAC.CF_HOLD = 0; + EagleRegAC.u.EagleAC.CF_BURST_RATE = 0; + } else { + EagleRegAC.u.EagleAC.CF_HOLD = 1; + EagleRegAC.u.EagleAC.CF_BURST_RATE = 1; + if (EagleRevision == 0x21) + EagleRegAC.u.EagleAC.CF_DOE = 0; + } + + // + // Set up the default L2 cache mode. + // Default to WRITE-THROUGH prior to Eagle 2.4, else WRITE-BACK + // + Mode = WriteThrough; + if (EagleRevision >= 0x24) { + Mode = WriteBack; + EagleRegA8.u.EagleA8.CF_LOOP_SNOOP = 1; + EagleRegA8.u.EagleA8.CF_CBA_MASK = 0x3f; + } + + if (HalpSystemType == MOTOROLA_BIG_BEND) { + EagleRegAC.u.EagleAC.CF_SNOOP_WS = 3; + EagleRegAC.u.EagleAC.CF_L2_HIT_DELAY = 1; + EagleRegAC.u.EagleAC.CF_TOE_WIDTH = 1; + + } else { + EagleRegAC.u.EagleAC.CF_SNOOP_WS = 2; + EagleRegAC.u.EagleAC.CF_FAST_CASTOUT = 1; + EagleRegAC.u.EagleAC.CF_L2_HIT_DELAY = 2; + } + + // + // There are IBM 604 parts (Revision 3.3 and earlier) that cannot burst + // at the fastest rate in WRITE-BACK mode. + // + if ((Mode == WriteBack) && (CpuType == MPC604) && (CpuRevision < 0x0304)) + EagleRegAC.u.EagleAC.CF_BURST_RATE = 1; // -2-2-2 + + + // + // Parse the environment variable "L2" + // + + if (HalGetEnvironmentVariable("L2", BUF_LEN, &CharBuffer[0]) == ESUCCESS) { + + // Copy L2 environment variable + i = 0; + while (L2_Parameter[i] = CharBuffer[i]) { + i++; + } + + for( Value = MyStrtok(CharBuffer, " :;,"); Value; Value = MyStrtok(NULL, " :;,") ) + { + if (*Value == NEGATECHAR) { + Value++; + Negate = TRUE; + } else + Negate = FALSE; + + // Check for L2 = "OFF" + if (HalpStrCmp( "OFF", Value )) + { + OemDisplayString("HAL: L2 cache is disabled via environment variable L2\n"); + HalpFlushAndDisableL2(); + PCR->SecondLevelDcacheSize = PCR->SecondLevelIcacheSize = 0; + return; + } + // Check for WriteBack + else if ( HalpStrCmp( "WB", Value ) ) + { + if (Negate) { + Value--; + goto ParseError; + } + Mode = WriteBack; + EagleRegA8.u.EagleA8.CF_LOOP_SNOOP = 1; + EagleRegA8.u.EagleA8.CF_CBA_MASK = 0x3f; + } + // Check for WriteThrough + else if ( HalpStrCmp( "WT", Value ) ) + { + if (Negate) { + Value--; + goto ParseError; + } + Mode = WriteThrough; + EagleRegA8.u.EagleA8.CF_LOOP_SNOOP = 0; + EagleRegA8.u.EagleA8.CF_CBA_MASK = 0x00; + } + else if (SynchronousSRAMs && HalpStrCmp("FAST_CASTOUT", Value)) { + if (Negate) { + EagleRegAC.u.EagleAC.CF_FAST_CASTOUT = 0; + } else + EagleRegAC.u.EagleAC.CF_FAST_CASTOUT = 1; + } + else if ( HalpStrCmp( "FAST_MODE", Value ) ) { + if (Negate) { + EagleRegAC.u.EagleAC.CF_FAST_L2_MODE = 0; + } else + EagleRegAC.u.EagleAC.CF_FAST_L2_MODE = 1; + } + // Check for cache timings + else if ( ( HalpStrCmp( "3-1-1-1", Value ) ) || + ( HalpStrCmp( "4-1-1-1", Value ) ) || + ( HalpStrCmp( "5-1-1-1", Value ) ) ) + { + if (Negate) { + Value--; + goto ParseError; + } + + EagleRegAC.u.EagleAC.CF_L2_HIT_DELAY = *Value - '2'; +// HIT_DELAY is where it samples HIT if =1, then 3-1-1-1 is fastest. +// CF_DOE_DELAY adds 1 more delay to # cycles, but doesn't change where +// HIT is sampled. If 66MHz or greater, then DOE_DELAY should be set. +// same thing with WRITE_DELAY. + + EagleRegAC.u.EagleAC.CF_SNOOP_WS = *Value - '2'; + if( SynchronousSRAMs ) // Asynchronous SRAMs can't do -1-1-1 + EagleRegAC.u.EagleAC.CF_BURST_RATE = 0; + } + else if ( ( HalpStrCmp( "3-2-2-2", Value ) ) || + ( HalpStrCmp( "4-2-2-2", Value ) ) || + ( HalpStrCmp( "5-2-2-2", Value ) ) ) + { + if (Negate) { + Value--; + goto ParseError; + } + + EagleRegAC.u.EagleAC.CF_L2_HIT_DELAY = *Value - '2'; + EagleRegAC.u.EagleAC.CF_SNOOP_WS = *Value - '2'; + EagleRegAC.u.EagleAC.CF_BURST_RATE = 1; + } else { + +ParseError: HalDisplayString("HAL: Error in L2 environment variable: "); + HalDisplayString(L2_Parameter); + HalDisplayString("\n illegal parameter begins here "); + for (i = 0; i < Value - CharBuffer; i++) + HalDisplayString("\304"); + HalDisplayString("^\n"); + break; + } + + } // End for + } // End If + + + // + // Enable L2 cache + // + OemDisplayString("HAL: L2 cache is "); + + if (L2_Cache_Size == 0) { + OemDisplayString("not installed.\n"); + return; + } + + if (Mode == WriteThrough) + EagleRegA8.u.EagleA8.CF_L2_MP = 1; + else + EagleRegA8.u.EagleA8.CF_L2_MP = 2; + + HalpWriteEagleUlong(0x800000A8, EagleRegA8.u.AsUlong); + HalpWriteEagleUlong(0x800000AC, EagleRegAC.u.AsUlong); + + switch (L2_Cache_Size) { + + case 256: + OemDisplayString("256 KB"); + break; + + case 512: + OemDisplayString("512 KB"); + break; + + case 1024: + OemDisplayString("1 MB"); + break; + + default: + OemDisplayString("an invalid configuration. Pattern = "); + HalpDisplayHex32(L2_Cache_Size, CharBuffer); + OemDisplayString(CharBuffer); + PCR->SecondLevelDcacheSize = PCR->SecondLevelDcacheSize = 0; + return; + } + + // + // Display cache mode and timing + // + if (Mode == WriteBack) + OemDisplayString(" (write-back "); + else + OemDisplayString(" (write-through "); + + CharBuffer[0] = (UCHAR) EagleRegAC.u.EagleAC.CF_L2_HIT_DELAY + '2'; + CharBuffer[1] = '\0'; + OemDisplayString(CharBuffer); + if (EagleRegAC.u.EagleAC.CF_BURST_RATE) + OemDisplayString("-2-2-2)\n"); + else + OemDisplayString("-1-1-1)\n"); + + return; +} + + + +ULONG HalpSizeL2Cache() +{ EAGLEAC EagleRegAC; + EAGLEA8 EagleRegA8; + CPU_TYPE CpuType; + + long BridgeChipId; + + BridgeChipId = HalpReadEagleUshort(0x80000002); + + // + // For non-EAGLE chips, firmware has set up the L2 cache size in + // the config block and NT Kernel has copied this info into PCR + // structure. So, no work needs to be done, retrieve the size from PCR + // + if (BridgeChipId != EAGLECHIPID) + return( (PCR->SecondLevelIcacheSize >> 10) ); + + // + // Set some fields in Eagle Register 0xA8 + // + EagleRegA8.u.AsUlong = HalpReadEagleUlong(0x800000A8); + + CpuType = (CPU_TYPE)(HalpGetProcessorVersion() >> 16); + switch (CpuType) { + + case MPC603: + case MPC603e: + EagleRegA8.u.EagleA8.PROC_TYPE = 2; + EagleRegA8.u.EagleA8.CF_BREAD_WS = 1; + break; + + case MPC604: + case MPC604e: + EagleRegA8.u.EagleA8.PROC_TYPE = 3; + EagleRegA8.u.EagleA8.CF_BREAD_WS = 0; + break; + + default: + return 0; // This HAL doesn't work with this processor + } + + HalpWriteEagleUlong(0x800000A8, EagleRegA8.u.AsUlong); + + EagleRegAC.u.AsUlong = HalpReadEagleUlong(0x800000AC); + EagleRegAC.u.EagleAC.CF_MOD_HIGH = 1; + HalpWriteEagleUlong(0x800000AC, EagleRegAC.u.AsUlong); + + return ( HalpSizeL2()); +} + + + + +BOOLEAN +HalpInitPlanar ( + VOID + ) + +{ ULONG j; + USHORT CpuRevision; + CPU_TYPE CpuType; + UCHAR EagleRevision, c; + UCHAR CharBuffer[20], i; + + long BridgeChipId; + + switch (HalpSystemType) { + + case MOTOROLA_BIG_BEND: + HalDisplayString("\nHAL: Motorola Big Bend System"); + break; + + case MOTOROLA_POWERSTACK: +// HalDisplayString("\nHAL: Motorola PowerStack System"); + break; + + case SYSTEM_UNKNOWN: + default: + HalDisplayString("\nHAL: WARNING : UNKNOWN SYSTEM TYPE\n"); + break; + + } + + OemDisplayString("\nHAL: Version 2.37 5/24/96."); + + CpuType = (CPU_TYPE)(HalpGetProcessorVersion() >> 16); + CpuRevision = (USHORT)(HalpGetProcessorVersion() & 0xFFFF); + + OemDisplayString("\nHAL: Processor is a 60"); + i = 0; + switch (CpuType) { + case MPC601: + case MPC603: + case MPC604: + CharBuffer[i++] = (UCHAR)(CpuType) + '0'; + break; + + case MPC603e: + CharBuffer[i++] = '3'; + CharBuffer[i++] = 'e'; + break; + + case MPC604e: + CharBuffer[i++] = '4'; + CharBuffer[i++] = 'e'; + break; + + default: + CharBuffer[i++] = '?'; + break; + } + CharBuffer[i] = '\0'; + OemDisplayString(CharBuffer); + + OemDisplayString(" revision "); + i = 0; + c = (UCHAR)((CpuRevision >> 8) & 0xf); + CharBuffer[i++] = c + '0'; + CharBuffer[i++] = '.'; + if (c = (UCHAR)((CpuRevision >> 4) & 0xf)) + CharBuffer[i++] = c + '0'; + c = (UCHAR)(CpuRevision & 0xf); + if (CpuType == MPC604 && c == 0) { // 604 v3.01 + CharBuffer[i++] = '0'; + CharBuffer[i++] = '1'; + } else { + CharBuffer[i++] = c + '0'; + } + CharBuffer[i] = '\0'; + OemDisplayString(CharBuffer); + + + BridgeChipId = HalpReadEagleUshort(0x80000002); + + if (BridgeChipId == EAGLECHIPID) + OemDisplayString("\nHAL: Eagle Revision"); + else + OemDisplayString("\nHAL: Bridge Chip Revision"); + + i = 0; + EagleRevision = HalpReadEagleUchar(0x80000008); + CharBuffer[i++] = ' '; + CharBuffer[i++] = (UCHAR) (EagleRevision >> 4) + '0'; + CharBuffer[i++] = '.'; + CharBuffer[i++] = (UCHAR) (EagleRevision & 0x0F) + '0'; + CharBuffer[i++] = '\n'; + CharBuffer[i] = '\0'; + OemDisplayString(CharBuffer); + + return TRUE; +} + + + +BOOLEAN +HalpMapPlanarSpace ( + VOID + ) + +/*++ + +Routine Description: + + This routine maps the interrupt acknowledge and error address + spaces for a PowerPC system. + +Arguments: + + None. + +Return Value: + + If the initialization is successfully completed, then a value of TRUE + is returned. Otherwise, a value of FALSE is returned. + +--*/ + +{ + PHYSICAL_ADDRESS physicalAddress; + + // + // Map interrupt control space. + // + + physicalAddress.HighPart = 0; + physicalAddress.LowPart = INTERRUPT_PHYSICAL_BASE; + HalpInterruptBase = MmMapIoSpace(physicalAddress, + PAGE_SIZE, + FALSE); + + if (HalpInterruptBase == NULL) + return FALSE; + else + return TRUE; + + + +} +BOOLEAN +HalpMapBusConfigSpace ( + VOID + ) + +/*++ + +Routine Description: + + This routine maps the HAL PCI config + spaces for a PowerPC system. + +Arguments: + + None. + +Return Value: + + If the initialization is successfully completed, then a value of TRUE + is returned. Otherwise, a value of FALSE is returned. + +--*/ + +{ + + + PHYSICAL_ADDRESS physicalAddress; + + + // + // Map the PCI config space. + // + + physicalAddress.LowPart = PCI_CONFIG_PHYSICAL_BASE; + HalpPciConfigBase = MmMapIoSpace(physicalAddress, HalpPciConfigSize, FALSE); + if (HalpPciConfigBase == NULL) + return FALSE; + else + return TRUE; + +} + +VOID +HalpHandleMemoryError( + VOID + ) + +{ + + UCHAR StatusByte; + ULONG ErrorAddress; + UCHAR TextAddress[11]; + USHORT EagleRegister, Byte; + + EagleRegister = HalpReadEagleUshort(0x80000006); + if (EagleRegister & 0x8100) + HalDisplayString("\nEAGLE Status Register: PARITY Error Detected."); + if (EagleRegister & 0x4000) + HalDisplayString("\nEAGLE Status Register: SERR asserted."); + +// MOTKJR 08/22/95 - Don't check for the following bit. +// It is always set when NT scans the slots on the PCI bus. +// if (EagleRegister & 0x2000) +// HalDisplayString("\nEAGLE Status Register: Transaction terminated with master-abort."); + + if (EagleRegister & 0x1000) + HalDisplayString("\nEAGLE Status Register: Transaction terminated by target-abort while master."); + if (EagleRegister & 0x0800) + HalDisplayString("\nEAGLE Status Register: Transaction terminated by target-abort while slave."); + + // + // Check Memory Error Detection Register 2 + // + StatusByte = HalpReadEagleUchar(0x800000C5); + + if (StatusByte & 0x10) { + HalDisplayString ("\nEAGLE Error Detection Register 2: L2 Parity Error Detected"); + } + + if (StatusByte & 0x80) { + // HalDisplayString ("\nEAGLE Error Detection Register 2: Invalid Error Address"); +#if DBG + // + // We have had a catastrophic hardware malfunction. + // Dump the state of the Eagle and HID 0 registers. + // + HalDisplayString("\n"); + HalpDumpHardwareState(); +#endif + return; + } + + // + // Read the error address register first + // + ErrorAddress = HalpReadEagleUlong(0x800000C8); + // + // Convert error address to HEX characters + // + HalpDisplayHex32(ErrorAddress, TextAddress); + TextAddress[ 8] = '.'; + TextAddress[ 9] = '\0'; + TextAddress[10] = '\0'; + + + // + // Check Memory Error Detection Register 1 + // + + StatusByte = HalpReadEagleUchar(0x800000C1); + + if (StatusByte & 0x08) { + HalDisplayString("\nEAGLE: PCI initiated Cycle."); + } else { + HalDisplayString("\nEAGLE: CPU initiated Cycle."); + } + + if (StatusByte & 0xC0) { + HalDisplayString ("\nEAGLE: PCI "); + if (StatusByte & 0x80) + HalDisplayString ("SERR"); + else + HalDisplayString ("target PERR"); + HalDisplayString (" signaled at address "); + HalDisplayString (TextAddress); + } + + if (StatusByte & 0x24) { + HalDisplayString ("\nEAGLE: Memory "); + if (StatusByte & 0x20) + HalDisplayString ("Select"); + else + HalDisplayString ("Read Parity"); + HalDisplayString (" error at address "); + HalDisplayString (TextAddress); + } + +#if DBG + // + // We have had a catastrophic hardware malfunction. + // Dump the state of the Eagle and HID 0 registers. + // + HalDisplayString("\n"); + HalpDumpHardwareState(); +#endif +} + + +VOID HalpEnableEagleSettings(VOID) +{ + ULONG EagleRegister, UseFirmwareSettings; + volatile ULONG FakeVectorFetch; + USHORT CpuRevision; + EAGLEC0 ErrorEnable1; + CPU_TYPE CpuType; + UCHAR EagleRevision; + UCHAR CharBuffer[BUF_LEN], *Value; + BOOLEAN Negate; + + long BridgeChipId; + +#define SetEagleUcharC0( Clear, Val ) \ + SetEagleReg(Clear, 0x800000C0, Val, HalpReadEagleRegC0, HalpWriteEagleUchar); + +#define SetEagleUchar( Clear, Offset, Val ) \ + SetEagleReg(Clear, Offset, Val, HalpReadEagleUchar, HalpWriteEagleUchar); + +#define SetEagleUshort( Clear, Offset, Val ) \ + SetEagleReg(Clear, Offset, Val, HalpReadEagleUshort, HalpWriteEagleUshort); + +#define SetEagleUlong( Clear, Offset, Val ) \ + SetEagleReg(Clear, Offset, Val, HalpReadEagleUlong, HalpWriteEagleUlong); + +#define SetEagleReg( Clear, Offset, Val, GetReg, SetReg) \ +{ \ + if (Clear) { \ + SetReg(Offset, GetReg(Offset) & ~Val); \ + } else { \ + SetReg(Offset, GetReg(Offset) | Val); \ + } \ +} + + CpuType = (CPU_TYPE)(HalpGetProcessorVersion() >> 16); + CpuRevision = (USHORT)(HalpGetProcessorVersion() & 0xFFFF); + EagleRevision = HalpReadEagleUchar(0x80000008); + UseFirmwareSettings = FALSE; + + // + // Adjust default settings for any known chip bugs or anomalies here. + // Eagle revision 2.1 has funny bits in Register C0. + // + + // + // If the bridge chip is not Eagle then set the revision number to 0x24 + // Currently the sister chip grackle is the only one supported by this + // code and it is equivalent to Eagle revision 0x24 + // + BridgeChipId = HalpReadEagleUshort(0x80000002); + if (BridgeChipId != EAGLECHIPID) + EagleRevision = 0x24; + + + if (EagleRevision == 0x21) + HalpReadEagleRegC0 = HalpReadEagleC0; + else + HalpReadEagleRegC0 = HalpReadEagleUchar; + + + // + // Set Address and Data Park bits in Eagle. + // These particular bits are not "parity" related. + // + HalpWriteEagleUlong(0x800000A8, HalpReadEagleUlong(0x800000A8) | 0x208); + + // + // Setup and initialize the default EAGLE Parity Checking. + // This default is platform dependent. + // + + switch (HalpSystemType) { + case MOTOROLA_POWERSTACK: + // + // PowerStack Systems will initialize EAGLE Parity Checking + // settings at the Boot ROM or ARC Firmware level. Use these + // EAGLE settings if they are present, otherwise use defaults. + // + UseFirmwareSettings = ((HalpReadEagleUlong(0x800000F0) & PCKEN) && + (HalpReadEagleRegC0(0x800000C0) & MRPE)); + if (UseFirmwareSettings) + break; + + HalpWriteEagleUchar(0x800000C4, 0x10); // Enable L2 Parity Checking. + // fall-through to default + + default: + + // + // Enable parity checking in Eagle chip + // + ErrorEnable1.u.AsUchar = 0; + ErrorEnable1.u.EagleC0.PCI_TARGET_ABORT = 1; + ErrorEnable1.u.EagleC0.MEM_SELECT_ERROR = 1; + ErrorEnable1.u.EagleC0.MEM_READ_PARITY = 1; + HalpWriteEagleUchar(0x800000C0, ErrorEnable1.u.AsUchar); + + if (EagleRevision >= 0x22) { + // + // NT must be loaded with the PCKEN bit enabled. Check PCKEN to make + // sure it is enabled. If it is not enabled, then don't enable parity + // checking since parity errors will be found all over memory. + // + EagleRegister = HalpReadEagleUlong(0x800000F0); + if (EagleRegister & PCKEN) { + + // + // Enable parity checking in Eagle chip + // + ErrorEnable1.u.EagleC0.LOCAL_BUS = 1; + HalpWriteEagleUchar(0x800000C0, ErrorEnable1.u.AsUchar); + + // + // Enable SERR checking in the Command register. + // + EagleRegister = HalpReadEagleUshort(0x80000004); + HalpWriteEagleUshort(0x80000004, (USHORT)(EagleRegister | 0x100)); // SERR only. + + // + // Conditionally enable Machine Check in the Eagle. + // Systems with IBM 604 revision 3.2 & 3.3 parts have problems + // with parity. Motorola parts are OK. It would be great if we + // could tell them apart (one from the other), but we can't. So, + // don't enable internal Cache parity on this (or earlier) parts. + // + if ((CpuType != MPC604) || (CpuRevision >= 0x0304)) { + EagleRegister = HalpReadEagleUlong(0x800000A8); + HalpWriteEagleUlong(0x800000A8, EagleRegister | MCP_EN); + } + } + } + } + + + // + // The environment variable "EAGLESETTINGS" is defined as: + // Matching a string serves to enable that feature while a tilde (~) + // immediately before the parameter string indicates that it is to be disabled. + // + + if ( HalGetEnvironmentVariable("EAGLESETTINGS", BUF_LEN, &CharBuffer[0]) == ESUCCESS ) { + + for( Value = MyStrtok(CharBuffer, " :;,"); Value; Value = MyStrtok(NULL, ":;,") ) { + + Negate = FALSE; + + if (*Value == NEGATECHAR) { + Value++; + Negate = TRUE; + } + + if (HalpStrCmp("MCP_EN", Value) || HalpStrCmp("MCP", Value)) { + SetEagleUlong( Negate, 0x800000A8, MCP_EN ); + + } else if (HalpStrCmp("TEA_EN", Value) || HalpStrCmp("TEA", Value)) { + SetEagleUlong( Negate, 0x800000A8, 0x400 ); + + } else if (HalpStrCmp("DPARK", Value) || HalpStrCmp("CF_DPARK", Value)) { + SetEagleUlong( Negate, 0x800000A8, 0x200 ); + + } else if (HalpStrCmp("GATHERING", Value)) { + SetEagleUlong( Negate, 0x800000A8, 0x040 ); + + } else if (HalpStrCmp("CF_LOOP_SNOOP", Value)) { + SetEagleUlong( Negate, 0x800000A8, 0x010 ); + + } else if (HalpStrCmp("APARK", Value) || HalpStrCmp("CF_APARK", Value)) { + SetEagleUlong( Negate, 0x800000A8, 0x008 ); + + } else if (HalpStrCmp("SPECULATIVE", Value)) { + SetEagleUlong( Negate, 0x800000A8, 0x004 ); + + } else if (HalpStrCmp("L2_PARITY", Value) || HalpStrCmp("L2", Value)) { + SetEagleUchar( Negate, 0x800000C4, 0x10 ); + + } else if (HalpStrCmp("PCKEN", Value)) { + SetEagleUlong( Negate, 0x800000F0, PCKEN ); + + } else if (HalpStrCmp("SERR", Value)) { + SetEagleUshort( Negate, 0x80000004, 0x100 ); + + } else if (HalpStrCmp("RX_SERR_EN", Value) || HalpStrCmp("RX_SERR", Value)) { + SetEagleUchar( Negate, 0x800000BA, 0x20 ); + + } else if (HalpStrCmp("TARGET_ABORT", Value)) { + SetEagleUcharC0( Negate, 0x80 ); + + } else if (HalpStrCmp("SLAVE_PERR", Value)) { + SetEagleUcharC0( Negate, 0x40 ); + SetEagleUshort( Negate, 0x80000004, 0x040 ); + + } else if (HalpStrCmp("SELECT_ERROR", Value) || HalpStrCmp("SELECT", Value)) { + SetEagleUcharC0( Negate, 0x20 ); + + } else if (HalpStrCmp("MASTER_PERR", Value)) { + SetEagleUcharC0( Negate, 0x10 ); + SetEagleUshort( Negate, 0x80000004, 0x040 ); + + } else if (HalpStrCmp("DRAM", Value) || HalpStrCmp("READ", Value) || HalpStrCmp("MEMORY", Value)) { + SetEagleUcharC0( Negate, MRPE ); + + } else if (HalpStrCmp("MASTER_ABORT", Value)) { + SetEagleUcharC0( Negate, 0x02 ); + + } else if (HalpStrCmp("LOCAL_ERROR", Value) || HalpStrCmp("LOCAL", Value)) { + SetEagleUcharC0( Negate, 0x01 ); + + // + // Enabling (or disabling) EAGLE parity by listing + // all of the individual bits was too complicated. + // For simplicity, we will define one pseudo-bit + // called "PARITY". This will set (or clear) all + // of the individual parity bits for EAGLE platforms. + // + } else if (HalpStrCmp("PARITY", Value)) { + // Conditionally turn on L2 checking. + if (HalpSystemType == MOTOROLA_POWERSTACK) { + SetEagleReg( Negate, 0x800000C4, 0x10, HalpReadEagleUchar, HalpWriteEagleUchar ); + } + + // Set or Clear the PCKEN bit. + SetEagleReg( Negate, 0x800000F0, PCKEN, HalpReadEagleUlong, HalpWriteEagleUlong ); + + // Set or Clear parity checking in Eagle chip + SetEagleUcharC0( Negate, 0xA5 ); + + // Set or Clear the SERR bit in the Command register. + SetEagleReg( Negate, 0x80000004, 0x100, HalpReadEagleUshort, HalpWriteEagleUshort ); + + // Set or Clear the MCP_EN last. + SetEagleReg( Negate, 0x800000A8, MCP_EN, HalpReadEagleUlong, HalpWriteEagleUlong ); + + } else if (HalpStrCmp("CF_ADDR_ONLY_DISABLE", Value)) { + SetEagleUlong( Negate, 0x800000AC, 0x4000); + } else if (HalpStrCmp("CF_BURST_RATE", Value)) { + SetEagleUlong( Negate, 0x800000AC, 0x0100); + } else if (HalpStrCmp("CF_FAST_CASTOUT", Value)) { + SetEagleUlong( Negate, 0x800000AC, 0x0080); + } else if (HalpStrCmp("CF_TOE_WIDTH", Value)) { + SetEagleUlong( Negate, 0x800000AC, 0x0040); + } else if (HalpStrCmp("CF_DOE", Value)) { + SetEagleUlong( Negate, 0x800000AC, 0x0002); + } else if (HalpStrCmp("CF_WDATA", Value)) { + SetEagleUlong( Negate, 0x800000AC, 0x0001); + + } else { + HalDisplayString( "HAL: Error in EAGLESETTINGS environment variable: "); + HalDisplayString(CharBuffer); + HalDisplayString("^\n"); + } + } // End for + } // End If + + // + // Initialize the PowerPC HID0 register here, + // before we clear the detection bits in the EAGLE. + // Otherwise we can miss the MCP pin signal transition. + // + HalpEnable_HID0_Settings(UseFirmwareSettings); + + // + // Clear any detection bits that may have been set while enabling L2 cache. + // The Eagle does not clear the MCP_ signal until it sees a fetch from + // the Machine Check vector. So, we must simulate a vector fetch. + // + FakeVectorFetch = *((volatile PULONG)(0x80000200)); // Clear the EAGLE MCP_ signal if it is set. + HalpWriteEagleUchar(0x800000C1, 0xFF); // Clear Error Detection Register 1. + HalpWriteEagleUchar(0x800000C5, 0xFF); // Clear Error Detection Register 2. + EagleRegister = HalpReadEagleUshort(0x80000006); // Get any Un-documented Status bits. + HalpWriteEagleUshort(0x80000006, 0xF900 | (USHORT)(EagleRegister)); // Clear Status Register Bits. + FakeVectorFetch = *((volatile PULONG)(0x80000200)); // Clear the EAGLE MCP_ signal if it is set. + + // + // Print this message last to confirm everything is working. + // + +} + +VOID HalpEnable_HID0_Settings(ULONG UseDefaultsHidSettings) +{ + ULONG EagleRegister; + USHORT CpuRevision; + CPU_TYPE CpuType; + UCHAR EagleRevision; + UCHAR CharBuffer[BUF_LEN], *Value; + ULONG HidEnable, HidDisable, CurrentHID0; + BOOLEAN Negate; + + long BridgeChipId; + +#define HID0_MCP (0x80000000) +#define HID0_CACHE (0x40000000) +#define HID0_ADDRESS (0x20000000) +#define HID0_DATA (0x10000000) +#define HID0_PAR (0x01000000) +#define HID0_DPM (0x00100000) +#define HID0_ILOCK (0x00002000) +#define HID0_DLOCK (0x00001000) +#define HID0_FBIOB (0x00000010) +#define HID0_BHT (0x00000004) + +#define SetCPUMask( Disable, Val ) \ +{ \ + if (Disable) \ + HidDisable |= Val; \ + else \ + HidEnable |= Val; \ +} + + CpuType = (CPU_TYPE)(HalpGetProcessorVersion() >> 16); + CpuRevision = (USHORT)(HalpGetProcessorVersion() & 0xFFFF); + + EagleRevision = HalpReadEagleUchar(0x80000008); + + // + // If the bridge chip is not Eagle then set the revision number to 0x24 + // Currently the sister chip grackle is the only one supported by this + // code and it is equivalent to Eagle revision 0x24 + // + BridgeChipId = HalpReadEagleUshort(0x80000002); + if (BridgeChipId != EAGLECHIPID) + EagleRevision = 0x24; + + + HidEnable = 0; + HidDisable = 0; + CurrentHID0 = HalpGetHID0(); + + switch (CpuType) { + case MPC603e: + if (CpuRevision <= 0x102) { + // + // Disable Dynamic Power Management on 603e revisions 1.1 & 1.2 + // 603e revisions 1.1 and 1.2 have errata w.r.t DPM. + // + CurrentHID0 &= ~HID0_DPM; + break; + } + // else fall through to 603 + + case MPC603: + // + // Enable Dynamic Power Management + // + CurrentHID0 |= HID0_DPM; + } + + // + // Set the default CPU Parity Checking. + // This default is platform dependent. + // + + switch (HalpSystemType) { + case MOTOROLA_POWERSTACK: + // + // PowerStack Systems will initialize HID0 Parity Checking + // settings at the Boot ROM or ARC Firmware level. Use these + // HID0 settings if they are present, otherwise use defaults. + // + if (UseDefaultsHidSettings) { + // Just enable the Machine Check Pin. + // Hopefully, everything else has been setup. + CurrentHID0 |= (HID0_MCP); + break; + } + // fall-through to default + + default: + CurrentHID0 &= ~(HID0_MCP | HID0_DATA | HID0_CACHE | HID0_ADDRESS); + + // + // Systems with IBM 604 revision 3.3 & 3.2 parts have problems with + // L1 parity checking. Motorola parts are OK, but we can't tell + // Motorola parts from IBM. So, don't enable L1 cache parity checking + // on 604 v3.3 or v3.2 parts. + switch (CpuType) { + case MPC604: + if (CpuRevision == 0x303 || CpuRevision == 0x302) + break; + // else fall through and enable Cache Parity + case MPC604e: + CurrentHID0 |= (HID0_CACHE); + // fall through + default: + break; + } + + // + // Set up the default Parity Checking. No checking prior to Eagle 2.2. + // NT must be loaded with the PCKEN bit enabled. Check PCKEN to make + // sure it is enabled. If it is not enabled, then don't enable parity + // checking since parity errors will be found all over memory. + // + + EagleRegister = HalpReadEagleUlong(0x800000F0); + if ((EagleRevision >= 0x22) && (EagleRegister & PCKEN)) { + // + // Systems with IBM 604 revision 3.3 parts have problems with + // parity generation. Motorola parts are OK. It would be great + // if we could tell them apart (one from the other), but we can't. + // So don't enable data parity checking on this (or earlier) parts. + // + if ((CpuType != MPC604) || (CpuRevision >= 0x0304)) + CurrentHID0 |= (HID0_MCP | HID0_DATA); + } + break; + } + + // + // The environment variable "HID0SETTINGS" is defined either as: + // "CACHE", "ADDRESS", "DATA", "MCP", "DPM" with either blank or semi-colon + // characters used as separators. Matching a string serves to enable + // that feature while a tilde (~) immediately before the parameter + // string indicates that it is to be disabled. + // + + if (HalGetEnvironmentVariable("HID0SETTINGS", BUF_LEN, &CharBuffer[0]) == ESUCCESS) { + for( Value = MyStrtok(CharBuffer, " :;,"); Value; Value = MyStrtok(NULL, ":;,") ) { + + Negate = FALSE; + + if (*Value == NEGATECHAR) { + Value++; + Negate = TRUE; + } + + if (HalpStrCmp("MCP", Value)) { + SetCPUMask(Negate, HID0_MCP); + } else if (HalpStrCmp("ADDRESS", Value)) { + SetCPUMask(Negate, HID0_ADDRESS); + } else if (HalpStrCmp("DATA", Value)) { + SetCPUMask(Negate, HID0_DATA); + } else if (HalpStrCmp("PAR", Value)) { + SetCPUMask(Negate, HID0_PAR); + } else if (HalpStrCmp("ILOCK", Value)) { + SetCPUMask(Negate, HID0_ILOCK); + } else if (HalpStrCmp("DLOCK", Value)) { + SetCPUMask(Negate, HID0_DLOCK); + } else { + switch (CpuType) { + case MPC604: + case MPC604e: + if (HalpStrCmp("BHT", Value)) { + SetCPUMask(Negate, HID0_BHT); + continue; + } + if (HalpStrCmp("CACHE", Value)) { + SetCPUMask(Negate, HID0_CACHE); + continue; + } + break; + + case MPC603: + case MPC603e: + if (HalpStrCmp("DPM", Value)) { + SetCPUMask(Negate, HID0_DPM); + continue; + } + if (HalpStrCmp("FBIOB", Value)) { + SetCPUMask(Negate, HID0_FBIOB); + continue; + } + break; + + + } // End switch + + HalDisplayString("HAL: Error in HID0SETTINGS environment variable: "); + HalDisplayString(CharBuffer); + HalDisplayString("\n"); + } // End else + + } // End for + } // End if + + // + // Check for inconsistencies in HID0SETTINGS + // + if (HidEnable & HidDisable) { + HalDisplayString("HAL: Inconsistent settings in HID0SETTINGS environment variable.\n"); + HalDisplayString(" Disable setting will override enable setting.\n"); + // + // Enforce DISABLE override ENABLE + // + HidEnable &= ~HidDisable; + } + + // + // Disable and Enable the bits in the HID0 register. + // + CurrentHID0 &= ~HidDisable; // Disable bits first. + HalpSetHID0(CurrentHID0); + + CurrentHID0 |= HidEnable; // Enable Bits last. + HalpSetHID0(CurrentHID0); + + // + // Print this message last to confirm everything is working. + // + +} + + +VOID HalpCheckHardwareRevisionLevels(VOID) +{ + ULONG EagleRegister, i; + USHORT CpuRevision; + CPU_TYPE CpuType; + UCHAR EagleRevision; + ARC_STATUS Status; + UCHAR Buffer[10]; + + long BridgeChipId; + + i = HalpGetProcessorVersion(); + CpuType = (CPU_TYPE)(i >> 16); + CpuRevision = (USHORT)(i & 0xFFFF); + + EagleRevision = HalpReadEagleUchar(0x80000008); + // + // Minimum hardware requirements: + // Eagle: v2.1 or greater + // 603 or 604: v3.2 or greater + // 603e or 604e: any CPU revision + // + + // + // If the bridge chip is not Eagle then set the revision number to 0x24 + // Currently the sister chip grackle is the only one supported by this + // code and it is equivalent to Eagle revision 0x24 + // + BridgeChipId = HalpReadEagleUshort(0x80000002); + if (BridgeChipId != EAGLECHIPID) + EagleRevision = 0x24; + + + if (EagleRevision >= 0x21) { + switch (CpuType) { + case MPC603: + case MPC604: + if (CpuRevision >= 0x0302) + return; + else + break; + + default: + return; + } + } + + // If the environment variable BOOTOLDHARDWARE exists (value is + // a don't care), then try to boot anyway. + Status = HalGetEnvironmentVariable("BOOTOLDHARDWARE", 5, Buffer); + if (Status == ESUCCESS || Status == ENOMEM) + return; + + HalDisplayString("\nHAL: Unsupported CPU and/or EAGLE revision level. Set the\n"); + HalDisplayString(" environment variable BOOTOLDHARDWARE to any value to boot anyway."); + + // + // Bug check - after stalling to allow + // any information printed on the screen + // to be read and seen by the user. + // + HalDisplayString("\n"); + for (i=0; i<12; i++) { + HalDisplayString("."); + KeStallExecutionProcessor(1000000); + } + + KeBugCheck(HAL_INITIALIZATION_FAILED); + return; +} + + + +VOID HalpDumpHardwareState(VOID) +{ ULONG EagleRegister, HID0; + UCHAR CharBuffer[12]; + +#if DBG + + if ( HalGetEnvironmentVariable("DBG_HAL", BUF_LEN, &CharBuffer[0]) == ESUCCESS ) { + + EagleRegister = HalpReadEagleUshort(0x80000004); + HalDisplayString("HAL: Eagle register 04 = 0x"); + HalpDisplayHex16(EagleRegister, CharBuffer ); + HalDisplayString(CharBuffer); + + EagleRegister = HalpReadEagleUshort(0x80000006); + HalDisplayString("HAL: Eagle register 06 = 0x"); + HalpDisplayHex16(EagleRegister, CharBuffer ); + HalDisplayString(CharBuffer); + + EagleRegister = HalpReadEagleUlong(0x800000A8); + HalDisplayString("HAL: Eagle register A8 = 0x"); + HalpDisplayHex32(EagleRegister, CharBuffer ); + HalDisplayString(CharBuffer); + + EagleRegister = HalpReadEagleUlong(0x800000AC); + HalDisplayString("HAL: Eagle register AC = 0x"); + HalpDisplayHex32(EagleRegister, CharBuffer ); + HalDisplayString(CharBuffer); + + EagleRegister = HalpReadEagleUchar(0x800000C0); + HalDisplayString("HAL: Eagle register C0 = 0x"); + HalpDisplayHex8(EagleRegister, CharBuffer ); + HalDisplayString(CharBuffer); + + EagleRegister = HalpReadEagleUchar(0x800000C1); + HalDisplayString("HAL: Eagle register C1 = 0x"); + HalpDisplayHex8(EagleRegister, CharBuffer ); + HalDisplayString(CharBuffer); + + EagleRegister = HalpReadEagleUchar(0x800000C3); + HalDisplayString("HAL: Eagle register C3 = 0x"); + HalpDisplayHex8(EagleRegister, CharBuffer ); + HalDisplayString(CharBuffer); + + EagleRegister = HalpReadEagleUchar(0x800000C4); + HalDisplayString("HAL: Eagle register C4 = 0x"); + HalpDisplayHex8(EagleRegister, CharBuffer ); + HalDisplayString(CharBuffer); + + EagleRegister = HalpReadEagleUchar(0x800000C5); + HalDisplayString("HAL: Eagle register C5 = 0x"); + HalpDisplayHex8(EagleRegister, CharBuffer ); + HalDisplayString(CharBuffer); + + EagleRegister = HalpReadEagleUchar(0x800000C7); + HalDisplayString("HAL: Eagle register C7 = 0x"); + HalpDisplayHex8(EagleRegister, CharBuffer ); + HalDisplayString(CharBuffer); + + EagleRegister = HalpReadEagleUlong(0x800000C8); + HalDisplayString("HAL: Eagle register C8 = 0x"); + HalpDisplayHex32(EagleRegister, CharBuffer ); + HalDisplayString(CharBuffer); + + HID0 = HalpGetHID0(); + HalDisplayString("HAL: PowerPC Register HID0 = 0x"); + HalpDisplayHex32(HID0, CharBuffer ); + HalDisplayString(CharBuffer); + } + +#endif + +} diff --git a/private/ntos/nthals/haleagle/ppc/pxmemctl.h b/private/ntos/nthals/haleagle/ppc/pxmemctl.h new file mode 100644 index 000000000..25f180ea6 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxmemctl.h @@ -0,0 +1,45 @@ +/*++ BUILD Version: 0001 // Increment this if a change has global effects + + +Module Name: + + pxmemctl.h + +Abstract: + + This header file defines the structures for the planar registers + on Masters systems. + + + + +Author: + + Jim Wooldridge + + +Revision History: + +--*/ + + +// +// define physical base addresses of planar +// + +#define INTERRUPT_PHYSICAL_BASE 0xbffffff0 // physical base of interrupt source +#define ERROR_ADDRESS_REGISTER 0xbfffeff0 + +#define IO_CONTROL_PHYSICAL_BASE 0x80000000 // physical base of IO control +#define SYSTEM_IO_CONTROL_SIZE 0x00008000 + + +typedef struct _PLANAR_CONTROL { + UCHAR Reserved[0xcf8]; + + ULONG ConfigAddress; // 0xcf8 + ULONG ConfigData; // 0xcfc + +} PLANAR_CONTROL, *PPLANAR_CONTROL; + + diff --git a/private/ntos/nthals/haleagle/ppc/pxmisc.s b/private/ntos/nthals/haleagle/ppc/pxmisc.s new file mode 100644 index 000000000..8e3b58ac7 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxmisc.s @@ -0,0 +1,183 @@ +//++ +// +// Copyright (c) 1993 IBM Corporation +// +// Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +// contains copyrighted material. Use of this file is restricted +// by the provisions of a Motorola Software License Agreement. +// +// Module Name: +// +// pxmisc.s +// +// Abstract: +// +// This module implements miscellaneous routines on the PowerPC. +// +// Author: +// +// Steve Johns (sjohns@pets.sps.mot.com) August 1994 +// +// Environment: +// +// Kernel mode only. +// + +#include "kxppc.h" + + .set HID0, 1008 // SPR # for HID0 + + + LEAF_ENTRY(HalpGetHID0) + + mfspr r.3, HID0 + + LEAF_EXIT(HalpGetHID0) + + + + + LEAF_ENTRY(HalpSetHID0) + + mtspr HID0, r.3 + + LEAF_EXIT(HalpSetHID0) + + + + +// ULONG HalpDivide ( +// IN ULARGE_INTEGER Dividend, +// IN ULONG Divisor) +// +// Routine Description: +// +// This function divides an unsigned large integer by an unsigned long +// and returns the resultant quotient. +// +// N.B. It is assumed that no overflow will occur. +// +// Arguments: +// +// Dividend (r.3, r.4) - Supplies the dividend value. +// (High-order bits in r.4, low-order bits in r.3) +// +// Divisor (r.5) - Supplies the divisor value. +// +// Return Value: +// +// The ULONG quotient is returned as the function value. +// +//-- + + + + .set Quotient, r.3 + .set DividendLo, r.3 + .set DividendHi, r.4 + .set Divisor, r.5 + .set Q1, r.11 + .set N, r.12 + .set Q0, N // Use of N & Q0 don't overlap + + LEAF_ENTRY(HalpDivide) + + + cmplw DividendHi,Divisor + bge overflow // catch overflow or division by 0 + cmplwi DividendHi,0 // test high part for 0 + bne Divide64Bits + +// High 32 bits of Dividend == 0, so use 32 bit division. + divwu Quotient,DividendLo,Divisor // Quotient = Dividend/Divisor + blr + +Divide64Bits: + + +// Normalize: Shift divisor and dividend left to get rid of leading zeroes +// in the divisor. Since DividendHi < Divisor, only zeroes are shifted out +// of the dividend. + cntlzw N,Divisor // number of bits to shift (N) + slw Divisor,Divisor,N // shift divisor + slw DividendHi,DividendHi,N // shift upper part of dividend + mr r.8, DividendLo // Save unshifted DividendLo + slw DividendLo,DividendLo,N // shift lower part of dividend + subfic N,N,32 // 32-N + srw N,r.8,N // leftmost N bits of DividendLo, slid right + or DividendHi,DividendHi,N // and inserted into low end of DividendHi + +// Estimate high-order halfword of quotient. If the dividend is +// A0 A1 A2 A3 and the divisor is B0 B1 (where each Ai or Bi is a halfword), +// then the estimate is A0 A1 0000 divided by B0 0000, or A0 A1 divided by B0. +// (DividendHi holds A0 A1, DividendLo holds A2 A3, and Divisor holds B0 B1.) +// The estimate may be too high because it does not account for B1; in rare +// cases, the estimate will not even fit in a halfword. High estimates are +// corrected for later. + srwi r.8,Divisor,16 // r.8 <- B0 + divwu Q0,DividendHi,r.8 // Q0 <- floor([A0 A1]/B0) +// Subtract partial quotient times divisor from dividend: If Q0 is the quotient +// computed above, this means that Q0 0000 times B0 B1 is subtracted from +// A0 A1 A2 A3. We compute Q0 times B0 B1 and then shift the two-word +// product left 16 bits. + mullw r.9,Q0,Divisor // low word of Q0 times B0 B1 + mulhwu r.10,Q0,Divisor // high word of Q0 times B0 B1 + slwi r.10,r.10,16 // shift high word left 16 bits + inslwi r.10,r.9,16,16 // move 16 bits from left of low word + // to right of high word + slwi r.9,r.9,16 // shift low word left 16 bits + subfc DividendLo,r.9,DividendLo // low word of difference + subfe DividendHi,r.10,DividendHi // high word of difference +// If the estimate for Q0 was too high, the difference will be negative. +// While A0 A1 A2 A3 is negative, repeatedly add B0 B1 0000 to A0 A1 A2 A3 +// and decrement Q0 by one to correct for the overestimate. + cmpwi DividendHi,0 // A0 A1 A2 A3 is negative iff A0 A1 is + bge Q0_okay // no correction needed + inslwi r.10,Divisor,16,16 // high word of B0 B1 0000 (= 0000 B0) + slwi r.9,Divisor,16 // low word of B0 B1 0000 (= B1 0000) +adjust_Q0: + addc DividendLo,DividendLo,r.9 // add B0 B1 0000 to A0 A1 A2 A3 (low) + adde DividendHi,DividendHi,r.10 // add B0 B1 0000 to A0 A1 A2 A3 (high) + cmpwi DividendHi,0 // Is A0 A1 A2 A3 now nonnegative? + addi Q0,Q0,-1 // decrement Q0 + blt adjust_Q0 // if A0 A1 A2 A3 still negative, repeat +Q0_okay: +// Estimate low-order halfword of quotient. A0 is necessarily 0000 at this +// point, so if the remaining part of the dividend is A0 A1 A2 A3 then the +// estimate is A1 A2 0000 divided by B0 0000, or A1 A2 divided by B0. +// (DividendHi holds A0 A1, DividendLo holds A2 A3, and r.8 holds B0.) + slwi r.9,DividendHi,16 // r.9 <- A1 0000 + inslwi r.9,DividendLo,16,16 // r.9 <- A1 A2 + divwu Q1,r.9,r.8 // Q1 <- floor([A1 A2]/B0) +// Subtract partial quotient times divisor from remaining part of dividend: +// If Q1 is the quotient computed above, this means +// that Q1 times B0 B1 is subtracted from A0 A1 A2 A3. We compute + mullw r.9,Q1,Divisor // low word of Q1 times B0 B1 + mulhwu r.10,Q1,Divisor // high word of Q1 times B0 B1 + subfc DividendLo,r.9,DividendLo // low word of difference + subfe DividendHi,r.10,DividendHi // high word of difference +// If the estimate for Q1 was too high, the difference will be negative. +// While A0 A1 A2 A3 is negative, repeatedly add B0 B1 to A0 A1 A2 A3 +// and decrement Q1 by one to correct for the overestimate. + cmpwi DividendHi,0 // A0 A1 A2 A3 is negative iff A0 A1 is + bge Q1_okay // no correction needed +adjust_Q1: + addc DividendLo,DividendLo,Divisor // add B0 B1 to A0 A1 A2 A3 (low) + addze DividendHi,DividendHi // add B0 B1 to A0 A1 A2 A3 (high) + cmpwi DividendHi,0 // Is A0 A1 A2 A3 now nonnegative? + addi Q1,Q1,-1 // decrement Q1 + blt adjust_Q1 // if A0 A1 A2 A3 still negative, repeat +Q1_okay: + slwi Quotient,Q0,16 // Quotient <- Q0 A1 + or Quotient,Quotient,Q1 + blr + + +// The error cases: +overflow: + li Quotient, 0 // return(0); + LEAF_EXIT(HalpDivide) + + + + diff --git a/private/ntos/nthals/haleagle/ppc/pxpcibrd.c b/private/ntos/nthals/haleagle/ppc/pxpcibrd.c new file mode 100644 index 000000000..91ef86864 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxpcibrd.c @@ -0,0 +1,544 @@ +/*++ + + +Copyright (C) 1989-1995 Microsoft Corporation + +Module Name: + + pxpcibrd.c + +Abstract: + + Get PCI-PCI bridge information + +Environment: + + Kernel mode + +--*/ + +#include "halp.h" +#include "pci.h" +#include "pcip.h" +#include "stdio.h" + +extern WCHAR rgzMultiFunctionAdapter[]; +extern WCHAR rgzConfigurationData[]; +extern WCHAR rgzIdentifier[]; +extern WCHAR rgzReservedResources[]; + + +#if DBG +#define DBGMSG(a) DbgPrint(a) +#else +#define DBGMSG(a) +#endif + + + +#define IsPciBridge(a) \ + (a->VendorID != PCI_INVALID_VENDORID && \ + PCI_CONFIG_TYPE(a) == PCI_BRIDGE_TYPE && \ + a->SubClass == 4 && a->BaseClass == 6) + + +typedef struct { + ULONG BusNo; + PBUS_HANDLER BusHandler; + PPCIPBUSDATA BusData; + PCI_SLOT_NUMBER SlotNumber; + PPCI_COMMON_CONFIG PciData; + ULONG IO, Memory, PFMemory; + UCHAR Buffer[PCI_COMMON_HDR_LENGTH]; +} CONFIGBRIDGE, *PCONFIGBRIDGE; + +// +// Internal prototypes +// + +VOID +HalpSetPciBridgedVgaCronk ( + IN ULONG BusNumber, + IN ULONG Base, + IN ULONG Limit + ); + + +ULONG +HalpGetBridgedPCIInterrupt ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ); + +ULONG +HalpGetBridgedPCIISAInt ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ); + +VOID +HalpPCIBridgedPin2Line ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER SlotNumber, + IN PPCI_COMMON_CONFIG PciData + ); + + +VOID +HalpPCIBridgedLine2Pin ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER SlotNumber, + IN PPCI_COMMON_CONFIG PciNewData, + IN PPCI_COMMON_CONFIG PciOldData + ); + +NTSTATUS +HalpGetBridgedPCIIrqTable ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER PciSlot, + OUT PUCHAR IrqTable + ); + + + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT,HalpGetPciBridgeConfig) +#pragma alloc_text(INIT,HalpSetPciBridgedVgaCronk) +#pragma alloc_text(INIT,HalpFixupPciSupportedRanges) +#endif + + +BOOLEAN +HalpGetPciBridgeConfig ( + IN ULONG HwType, + IN PUCHAR MaxPciBus + ) +/*++ + +Routine Description: + + Scan the devices on all known pci buses trying to locate any + PCI to PCI bridges. Record the hierarchy for the buses, and + which buses have what addressing limits. + +Arguments: + + HwType - Configuration type. + MaxPciBus - # of PCI buses reported by the bios + +--*/ +{ + PBUS_HANDLER ChildBus; + PPCIPBUSDATA ChildBusData; + ULONG d, f, i, j, BusNo; + UCHAR Rescan; + BOOLEAN FoundDisabledBridge; + CONFIGBRIDGE CB; + + Rescan = 0; + FoundDisabledBridge = FALSE; + + // + // Find each bus on a bridge and initialize it's base and limit information + // + + CB.PciData = (PPCI_COMMON_CONFIG) CB.Buffer; + CB.SlotNumber.u.bits.Reserved = 0; + for (BusNo=0; BusNo < *MaxPciBus; BusNo++) { + + CB.BusHandler = HalpHandlerForBus (PCIBus, BusNo); + CB.BusData = (PPCIPBUSDATA) CB.BusHandler->BusData; + + for (d = 0; d < PCI_MAX_DEVICES; d++) { + CB.SlotNumber.u.bits.DeviceNumber = d; + + for (f = 0; f < PCI_MAX_FUNCTION; f++) { + CB.SlotNumber.u.bits.FunctionNumber = f; + + // + // Read PCI configuration information + // + + HalpReadPCIConfig ( + CB.BusHandler, + CB.SlotNumber, + CB.PciData, + 0, + PCI_COMMON_HDR_LENGTH + ); + + if (CB.PciData->VendorID == PCI_INVALID_VENDORID) { + // next device + break; + } + + if (!IsPciBridge (CB.PciData)) { + // not a PCI-PCI bridge, next function + continue; + } + + if (!(CB.PciData->Command & PCI_ENABLE_BUS_MASTER)) { + // this PCI bridge is not enabled - skip it for now + FoundDisabledBridge = TRUE; + continue; + } + + if ((ULONG) CB.PciData->u.type1.PrimaryBus != + CB.BusHandler->BusNumber) { + + DBGMSG ("HAL GetPciData: bad primarybus!!!\n"); + // what to do? + } + + // + // Found a PCI-PCI bridge. Determine it's parent child relationships + // + + ChildBus = HalpHandlerForBus (PCIBus, CB.PciData->u.type1.SecondaryBus); + if (!ChildBus) { + DBGMSG ("HAL GetPciData: found configured PCI bridge\n"); + + // up the number of buses + if (CB.PciData->u.type1.SecondaryBus > Rescan) { + Rescan = CB.PciData->u.type1.SecondaryBus; + } + continue; + } + + ChildBusData = (PPCIPBUSDATA) ChildBus->BusData; + if (ChildBusData->BridgeConfigRead) { + // this child buses relationships already processed + continue; + } + + // + // Remember the limits which are programmed into this bridge + // + + ChildBusData->BridgeConfigRead = TRUE; + HalpSetBusHandlerParent (ChildBus, CB.BusHandler); + ChildBusData->ParentBus = (UCHAR) CB.BusHandler->BusNumber; + ChildBusData->CommonData.ParentSlot = CB.SlotNumber; + + ChildBus->BusAddresses->IO.Base = + PciBridgeIO2Base( + CB.PciData->u.type1.IOBase, + CB.PciData->u.type1.IOBaseUpper16 + ); + + ChildBus->BusAddresses->IO.Limit = + PciBridgeIO2Limit( + CB.PciData->u.type1.IOLimit, + CB.PciData->u.type1.IOLimitUpper16 + ); + + // + // Special VGA address remapping occuring on this bridge? + // + + if (CB.PciData->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_VGA && + ChildBus->BusAddresses->IO.Base < ChildBus->BusAddresses->IO.Limit) { + + HalpSetPciBridgedVgaCronk ( + ChildBus->BusNumber, + (ULONG) ChildBus->BusAddresses->IO.Base, + (ULONG) ChildBus->BusAddresses->IO.Limit + ); + } + + // + // If supported I/O ranges on this bus are limited to + // 256 bytes on every 1K aligned boundary within the + // range, then redo supported IO BusAddresses to match + // + + if (CB.PciData->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_ISA && + ChildBus->BusAddresses->IO.Base < ChildBus->BusAddresses->IO.Limit) { + + // assume Base is 1K aligned + i = (ULONG) ChildBus->BusAddresses->IO.Base; + j = (ULONG) ChildBus->BusAddresses->IO.Limit; + + // convert head entry + ChildBus->BusAddresses->IO.Limit = i + 256; + i += 1024; + + // add remaining ranges + while (i < j) { + HalpAddRange ( + &ChildBus->BusAddresses->IO, + 1, // address space + 0, // system base + i, // bus address + i + 256 // bus limit + ); + + // next range + i += 1024; + } + } + + ChildBus->BusAddresses->Memory.Base = + PciBridgeMemory2Base(CB.PciData->u.type1.MemoryBase); + + ChildBus->BusAddresses->Memory.Limit = + PciBridgeMemory2Limit(CB.PciData->u.type1.MemoryLimit); + + // On x86 it's ok to clip Prefetch to 32 bits + + if (CB.PciData->u.type1.PrefetchBaseUpper32 == 0) { + ChildBus->BusAddresses->PrefetchMemory.Base = + PciBridgeMemory2Base(CB.PciData->u.type1.PrefetchBase); + + + ChildBus->BusAddresses->PrefetchMemory.Limit = + PciBridgeMemory2Limit(CB.PciData->u.type1.PrefetchLimit); + + if (CB.PciData->u.type1.PrefetchLimitUpper32) { + ChildBus->BusAddresses->PrefetchMemory.Limit = 0xffffffff; + } + } + + // should call HalpAssignPCISlotResources to assign + // baseaddresses, etc... + } + } + } + + if (Rescan) { + *MaxPciBus = Rescan; + return TRUE; + } + + if (!FoundDisabledBridge) { + return FALSE; + } + + DBGMSG ("HAL GetPciData: found disabled pci bridge\n"); + + return FALSE; +} + +VOID +HalpFixupPciSupportedRanges ( + IN ULONG MaxBuses + ) +/*++ + +Routine Description: + + PCI-PCI bridged buses only see addresses which their parent + buses supports. So adjust any PCI SUPPORT_RANGES to be + a complete subset of all of it's parent buses. + + PCI-PCI briges use postive address decode to forward addresses. + So, remove any addresses from any PCI bus which are bridged to + a child PCI bus. + +--*/ +{ + ULONG i; + PBUS_HANDLER Bus, ParentBus; + PSUPPORTED_RANGES HRanges; + + // + // Pass 1 - shrink all PCI supported ranges to be a subset of + // all of it's parent buses + // + + for (i = 0; i < MaxBuses; i++) { + + Bus = HalpHandlerForBus (PCIBus, i); + + ParentBus = Bus->ParentHandler; + while (ParentBus) { + + HRanges = Bus->BusAddresses; + Bus->BusAddresses = HalpMergeRanges ( + ParentBus->BusAddresses, + HRanges + ); + + HalpFreeRangeList (HRanges); + ParentBus = ParentBus->ParentHandler; + } + } + + // + // Pass 2 - remove all child PCI bus ranges from parent PCI buses + // + + for (i = 0; i < MaxBuses; i++) { + Bus = HalpHandlerForBus (PCIBus, i); + + ParentBus = Bus->ParentHandler; + while (ParentBus) { + + if (ParentBus->InterfaceType == PCIBus) { + HalpRemoveRanges ( + ParentBus->BusAddresses, + Bus->BusAddresses + ); + } + + ParentBus = ParentBus->ParentHandler; + } + } + + // + // Cleanup + // + + for (i = 0; i < MaxBuses; i++) { + Bus = HalpHandlerForBus (PCIBus, i); + HalpConsolidateRanges (Bus->BusAddresses); + } +} + + + +VOID +HalpSetPciBridgedVgaCronk ( + IN ULONG BusNumber, + IN ULONG BaseAddress, + IN ULONG LimitAddress + ) +/*++ + +Routine Description: . + + The 'vga compatible addresses' bit is set in the bridge control register. + This causes the bridge to pass any I/O address in the range of: 10bit + decode 3b0-3bb & 3c0-3df, as TEN bit addresses. + + As far as I can tell this "feature" is an attempt to solve some problem + which the folks solving it did not fully understand, so instead of doing + it right we have this fine mess. + + The solution is to take the least of all evils which is to remove any + I/O port ranges which are getting remapped from any IoAssignResource + request. (ie, IoAssignResources will never contemplate giving any + I/O port out in the suspected ranges). + + note: memory allocation error here is fatal so don't bother with the + return codes. + +Arguments: + + Base - Base of IO address range in question + Limit - Limit of IO address range in question + +--*/ +{ + UNICODE_STRING unicodeString; + OBJECT_ATTRIBUTES objectAttributes; + HANDLE handle; + ULONG Length; + PCM_RESOURCE_LIST ResourceList; + PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor; + ULONG AddressMSBs; + WCHAR ValueName[80]; + NTSTATUS status; + + // + // Open reserved resource settings + // + + RtlInitUnicodeString (&unicodeString, rgzReservedResources); + InitializeObjectAttributes( &objectAttributes, + &unicodeString, + OBJ_CASE_INSENSITIVE, + NULL, + (PSECURITY_DESCRIPTOR) NULL + ); + + status = ZwOpenKey( &handle, KEY_READ|KEY_WRITE, &objectAttributes); + if (!NT_SUCCESS(status)) { + return; + } + + // + // Build resource list of reserved ranges + // + + Length = ((LimitAddress - BaseAddress) / 1024 + 2) * 2 * + sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR) + + sizeof (CM_RESOURCE_LIST); + + ResourceList = (PCM_RESOURCE_LIST) ExAllocatePool (PagedPool, Length); + memset (ResourceList, 0, Length); + + ResourceList->Count = 1; + ResourceList->List[0].InterfaceType = PCIBus; + ResourceList->List[0].BusNumber = BusNumber; + Descriptor = ResourceList->List[0].PartialResourceList.PartialDescriptors; + + while (BaseAddress < LimitAddress) { + AddressMSBs = BaseAddress & ~0x3ff; // get upper 10bits of addr + + // + // Add xx3b0 through xx3bb + // + + Descriptor->Type = CmResourceTypePort; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + Descriptor->Flags = CM_RESOURCE_PORT_IO; + Descriptor->u.Port.Start.QuadPart = AddressMSBs | 0x3b0; + Descriptor->u.Port.Length = 0xb; + + Descriptor += 1; + ResourceList->List[0].PartialResourceList.Count += 1; + + // + // Add xx3c0 through xx3df + // + + Descriptor->Type = CmResourceTypePort; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + Descriptor->Flags = CM_RESOURCE_PORT_IO; + Descriptor->u.Port.Start.QuadPart = AddressMSBs | 0x3c0; + Descriptor->u.Port.Length = 0x1f; + + Descriptor += 1; + ResourceList->List[0].PartialResourceList.Count += 1; + + // + // Next range + // + + BaseAddress += 1024; + } + + // + // Add the reserved ranges to avoid during IoAssignResource + // + + swprintf (ValueName, L"HAL_PCI_%d", BusNumber); + RtlInitUnicodeString (&unicodeString, ValueName); + + ZwSetValueKey (handle, + &unicodeString, + 0L, + REG_RESOURCE_LIST, + ResourceList, + (ULONG) Descriptor - (ULONG) ResourceList + ); + + + ExFreePool (ResourceList); + ZwClose (handle); +} + + diff --git a/private/ntos/nthals/haleagle/ppc/pxpcibus.c b/private/ntos/nthals/haleagle/ppc/pxpcibus.c new file mode 100644 index 000000000..a7f1f4b4f --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxpcibus.c @@ -0,0 +1,2289 @@ +/*++ + + +Copyright (C) 1989-1995 Microsoft Corporation + +Module Name: + + pxpcibus.c + +Abstract: + + Get/Set bus data routines for the PCI bus + +Author: + + Ken Reneris (kenr) 14-June-1994 + Jim Wooldridge Port to PowerPC + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#include "halp.h" +#include "pci.h" +#include "pcip.h" + +#include "pxmemctl.h" +#include "pxpcisup.h" + +extern WCHAR rgzMultiFunctionAdapter[]; +extern WCHAR rgzConfigurationData[]; +extern WCHAR rgzIdentifier[]; +extern WCHAR rgzPCIIdentifier[]; + +extern ULONG HalpPciMaxSlots; + +typedef ULONG (*FncConfigIO) ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +typedef VOID (*FncSync) ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PKIRQL Irql, + IN PVOID State + ); + +typedef VOID (*FncReleaseSync) ( + IN PBUS_HANDLER BusHandler, + IN KIRQL Irql + ); + +typedef struct _PCI_CONFIG_HANDLER { + FncSync Synchronize; + FncReleaseSync ReleaseSynchronzation; + FncConfigIO ConfigRead[3]; + FncConfigIO ConfigWrite[3]; +} PCI_CONFIG_HANDLER, *PPCI_CONFIG_HANDLER; + + + +// +// Prototypes +// + +ULONG +HalpGetPCIData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER SlotNumber, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +ULONG +HalpSetPCIData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER SlotNumber, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +NTSTATUS +HalpAssignPCISlotResources ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PUNICODE_STRING RegistryPath, + IN PUNICODE_STRING DriverClassName OPTIONAL, + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT DeviceObject OPTIONAL, + IN ULONG SlotNumber, + IN OUT PCM_RESOURCE_LIST *AllocatedResources + ); + +VOID +HalpInitializePciBus ( + VOID + ); + +BOOLEAN +HalpIsValidPCIDevice ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot + ); + +BOOLEAN +HalpValidPCISlot ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot + ); + +//------------------------------------------------- + +VOID HalpPCISynchronizeType1 ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PKIRQL Irql, + IN PVOID State + ); + +VOID HalpPCIReleaseSynchronzationType1 ( + IN PBUS_HANDLER BusHandler, + IN KIRQL Irql + ); + +ULONG HalpPCIReadUlongType1 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIReadUcharType1 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIReadUshortType1 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIWriteUlongType1 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIWriteUcharType1 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIWriteUshortType1 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +VOID HalpPCISynchronizeType2 ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PKIRQL Irql, + IN PVOID State + ); + +VOID HalpPCIReleaseSynchronzationType2 ( + IN PBUS_HANDLER BusHandler, + IN KIRQL Irql + ); + +ULONG HalpPCIReadUlongType2 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIReadUcharType2 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIReadUshortType2 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIWriteUlongType2 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIWriteUcharType2 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIWriteUshortType2 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + + +// +// Globals +// + +KSPIN_LOCK HalpPCIConfigLock; + +PCI_CONFIG_HANDLER PCIConfigHandler; + +PCI_CONFIG_HANDLER PCIConfigHandlerType1 = { + HalpPCISynchronizeType1, + HalpPCIReleaseSynchronzationType1, + { + HalpPCIReadUlongType1, // 0 + HalpPCIReadUcharType1, // 1 + HalpPCIReadUshortType1 // 2 + }, + { + HalpPCIWriteUlongType1, // 0 + HalpPCIWriteUcharType1, // 1 + HalpPCIWriteUshortType1 // 2 + } +}; + +PCI_CONFIG_HANDLER PCIConfigHandlerType2 = { + HalpPCISynchronizeType2, + HalpPCIReleaseSynchronzationType2, + { + HalpPCIReadUlongType2, // 0 + HalpPCIReadUcharType2, // 1 + HalpPCIReadUshortType2 // 2 + }, + { + HalpPCIWriteUlongType2, // 0 + HalpPCIWriteUcharType2, // 1 + HalpPCIWriteUshortType2 // 2 + } +}; + +UCHAR PCIDeref[4][4] = { {0,1,2,2},{1,1,1,1},{2,1,2,2},{1,1,1,1} }; + +VOID +HalpPCIConfig ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length, + IN FncConfigIO *ConfigIO + ); + +#if DBG +#define DBGMSG(a) DbgPrint(a) +VOID +HalpTestPci ( + ULONG + ); +#else +#define DBGMSG(a) +#endif + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT,HalpInitializePciBus) +#pragma alloc_text(INIT,HalpAllocateAndInitPciBusHandler) +#pragma alloc_text(INIT,HalpIsValidPCIDevice) +#pragma alloc_text(PAGE,HalpAssignPCISlotResources) +#endif + + + +VOID +HalpInitializePciBus ( + VOID + ) +{ + PPCI_REGISTRY_INFO PCIRegInfo; + UNICODE_STRING unicodeString, ConfigName, IdentName; + OBJECT_ATTRIBUTES objectAttributes; + HANDLE hMFunc, hBus; + NTSTATUS status; + UCHAR buffer [sizeof(PPCI_REGISTRY_INFO) + 99]; + PWSTR p; + WCHAR wstr[8]; + ULONG i, d, junk, HwType; + PBUS_HANDLER BusHandler; + PCI_SLOT_NUMBER SlotNumber; + PKEY_VALUE_FULL_INFORMATION ValueInfo; + PCM_FULL_RESOURCE_DESCRIPTOR Desc; + PCM_PARTIAL_RESOURCE_DESCRIPTOR PDesc; + + + // + // Search the hardware description looking for any reported + // PCI bus. The first ARC entry for a PCI bus will contain + // the PCI_REGISTRY_INFO. + + RtlInitUnicodeString (&unicodeString, rgzMultiFunctionAdapter); + InitializeObjectAttributes ( + &objectAttributes, + &unicodeString, + OBJ_CASE_INSENSITIVE, + NULL, // handle + NULL); + + + status = ZwOpenKey (&hMFunc, KEY_READ, &objectAttributes); + if (!NT_SUCCESS(status)) { + return ; + } + + unicodeString.Buffer = wstr; + unicodeString.MaximumLength = sizeof (wstr); + + RtlInitUnicodeString (&ConfigName, rgzConfigurationData); + RtlInitUnicodeString (&IdentName, rgzIdentifier); + + ValueInfo = (PKEY_VALUE_FULL_INFORMATION) buffer; + + for (i=0; TRUE; i++) { + RtlIntegerToUnicodeString (i, 10, &unicodeString); + InitializeObjectAttributes ( + &objectAttributes, + &unicodeString, + OBJ_CASE_INSENSITIVE, + hMFunc, + NULL); + + status = ZwOpenKey (&hBus, KEY_READ, &objectAttributes); + if (!NT_SUCCESS(status)) { + // + // Out of Multifunction adapter entries... + // + + ZwClose (hMFunc); + return ; + } + + // + // Check the Indentifier to see if this is a PCI entry + // + + status = ZwQueryValueKey ( + hBus, + &IdentName, + KeyValueFullInformation, + ValueInfo, + sizeof (buffer), + &junk + ); + + if (!NT_SUCCESS (status)) { + ZwClose (hBus); + continue; + } + + p = (PWSTR) ((PUCHAR) ValueInfo + ValueInfo->DataOffset); + if (p[0] != L'P' || p[1] != L'C' || p[2] != L'I' || p[3] != 0) { + ZwClose (hBus); + continue; + } + + // + // The first PCI entry has the PCI_REGISTRY_INFO structure + // attached to it. + // + + status = ZwQueryValueKey ( + hBus, + &ConfigName, + KeyValueFullInformation, + ValueInfo, + sizeof (buffer), + &junk + ); + + ZwClose (hBus); + if (!NT_SUCCESS(status)) { + continue ; + } + + Desc = (PCM_FULL_RESOURCE_DESCRIPTOR) ((PUCHAR) + ValueInfo + ValueInfo->DataOffset); + PDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR) + Desc->PartialResourceList.PartialDescriptors); + + if (PDesc->Type == CmResourceTypeDeviceSpecific) { + // got it.. + PCIRegInfo = (PPCI_REGISTRY_INFO) (PDesc+1); + break; + } + } + + // + // Initialize spinlock for synchronizing access to PCI space + // + + KeInitializeSpinLock (&HalpPCIConfigLock); + + // + // PCIRegInfo describes the system's PCI support as indicated by the BIOS. + // + + HwType = PCIRegInfo->HardwareMechanism & 0xf; + +#if 0 + // + // Some AMI bioses claim machines are Type2 configuration when they + // are really type1. If this is a Type2 with at least one bus, + // try to verify it's not really a type1 bus + // + + if (PCIRegInfo->NoBuses && HwType == 2) { + + // + // Check each slot for a valid device. Which every style configuration + // space shows a valid device first will be used + // + + SlotNumber.u.bits.Reserved = 0; + SlotNumber.u.bits.FunctionNumber = 0; + + for (d = 0; d < PCI_MAX_DEVICES; d++) { + SlotNumber.u.bits.DeviceNumber = d; + + // + // First try what the BIOS claims - type 2. Allocate type2 + // test handle for PCI bus 0. + // + + HwType = 2; + BusHandler = HalpAllocateAndInitPciBusHandler (HwType, 0, TRUE); + + if (HalpIsValidPCIDevice (BusHandler, SlotNumber)) { + break; + } + + // + // Valid device not found on Type2 access for this slot. + // Reallocate the bus handler are Type1 and take a look. + // + + HwType = 1; + BusHandler = HalpAllocateAndInitPciBusHandler (HwType, 0, TRUE); + + if (HalpIsValidPCIDevice (BusHandler, SlotNumber)) { + break; + } + + HwType = 2; + } + + // + // Reset handler for PCI bus 0 to whatever style config space + // was finally decided. + // + + HalpAllocateAndInitPciBusHandler (HwType, 0, FALSE); + } +#endif + + + // + // For each PCI bus present, allocate a handler structure and + // fill in the dispatch functions + // + + do { + for (i=0; i < PCIRegInfo->NoBuses; i++) { + + // + // If handler not already built, do it now + // + + if (!HalpHandlerForBus (PCIBus, i)) { + HalpAllocateAndInitPciBusHandler (HwType, i, FALSE); + } + } + + // + // Bus handlers for all PCI buses have been allocated, go collect + // pci bridge information. + // + + } while (HalpGetPciBridgeConfig (HwType, &PCIRegInfo->NoBuses)) ; + + // + // Fixup SUPPORTED_RANGES + // + + HalpFixupPciSupportedRanges (PCIRegInfo->NoBuses); + +#if DBG + HalpTestPci (0); +#endif +} + + +PBUS_HANDLER +HalpAllocateAndInitPciBusHandler ( + IN ULONG HwType, + IN ULONG BusNo, + IN BOOLEAN TestAllocation + ) +{ + PBUS_HANDLER Bus; + PPCIPBUSDATA BusData; + + Bus = HalpAllocateBusHandler ( + PCIBus, // Interface type + PCIConfiguration, // Has this configuration space + BusNo, // bus # + Internal, // child of this bus + 0, // and number + sizeof (PCIPBUSDATA) // sizeof bus specific buffer + ); + + // + // Fill in PCI handlers + // + + Bus->GetBusData = (PGETSETBUSDATA) HalpGetPCIData; + Bus->SetBusData = (PGETSETBUSDATA) HalpSetPCIData; + Bus->GetInterruptVector = (PGETINTERRUPTVECTOR) HalpGetPCIIntOnISABus; + Bus->AdjustResourceList = (PADJUSTRESOURCELIST) HalpAdjustPCIResourceList; + Bus->AssignSlotResources = (PASSIGNSLOTRESOURCES) HalpAssignPCISlotResources; + Bus->BusAddresses->Dma.Limit = 0; + + BusData = (PPCIPBUSDATA) Bus->BusData; + + // + // Fill in common PCI data + // + + BusData->CommonData.Tag = PCI_DATA_TAG; + BusData->CommonData.Version = PCI_DATA_VERSION; + BusData->CommonData.ReadConfig = (PciReadWriteConfig) HalpReadPCIConfig; + BusData->CommonData.WriteConfig = (PciReadWriteConfig) HalpWritePCIConfig; + BusData->CommonData.Pin2Line = (PciPin2Line) HalpPCIPin2ISALine; + BusData->CommonData.Line2Pin = (PciLine2Pin) HalpPCIISALine2Pin; + + // + // Set defaults + // + + Bus->BusAddresses->Memory.Limit = 0x3EFFFFFF; + Bus->BusAddresses->IO.Limit = 0x3F7FFFFF; + BusData->GetIrqRange = (PciIrqRange) HalpGetISAFixedPCIIrq; + + RtlInitializeBitMap (&BusData->DeviceConfigured, + BusData->ConfiguredBits, 256); + + switch (HwType) { + case 1: + // + // Initialize access port information for Type1 handlers + // direct Method. + // + + RtlCopyMemory (&PCIConfigHandler, + &PCIConfigHandlerType1, + sizeof (PCIConfigHandler)); + + BusData->MaxDevice = HalpPciMaxSlots; + break; + + case 2: + // + // Initialize access port information for Type2 handlers + // indirect Method. + // + + RtlCopyMemory (&PCIConfigHandler, + &PCIConfigHandlerType2, + sizeof (PCIConfigHandler)); + + // + // Allow access all 32 devices per bus. + // + BusData->MaxDevice = PCI_MAX_DEVICES; + break; + + default: + // unsupport type + DBGMSG ("HAL: Unkown PCI type\n"); + } + + if (!TestAllocation) { +#ifdef SUBCLASSPCI + HalpSubclassPCISupport (Bus, HwType); +#endif + } + + return Bus; +} + +BOOLEAN +HalpIsValidPCIDevice ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot + ) +/*++ + +Routine Description: + + Reads the device configuration data for the given slot and + returns TRUE if the configuration data appears to be valid for + a PCI device; otherwise returns FALSE. + +Arguments: + + BusHandler - Bus to check + Slot - Slot to check + +--*/ + +{ + PPCI_COMMON_CONFIG PciData; + UCHAR iBuffer[PCI_COMMON_HDR_LENGTH]; + ULONG i, j; + + + PciData = (PPCI_COMMON_CONFIG) iBuffer; + + // + // Read device common header + // + + HalpReadPCIConfig (BusHandler, Slot, PciData, 0, PCI_COMMON_HDR_LENGTH); + + // + // Valid device header? + // + + if (PciData->VendorID == PCI_INVALID_VENDORID || + PCI_CONFIG_TYPE (PciData) != PCI_DEVICE_TYPE) { + + return FALSE; + } + + // + // Check fields for reasonable values + // + + if ((PciData->u.type0.InterruptPin && PciData->u.type0.InterruptPin > 4) || + (PciData->u.type0.InterruptLine & 0x70)) { + return FALSE; + } + + for (i=0; i < PCI_TYPE0_ADDRESSES; i++) { + j = PciData->u.type0.BaseAddresses[i]; + + if (j & PCI_ADDRESS_IO_SPACE) { + if (j > 0xffff) { + // IO port > 64k? + return FALSE; + } + } else { + if (j > 0xf && j < 0x80000) { + // Mem address < 0x8000h? + return FALSE; + } + } + + if (Is64BitBaseAddress(j)) { + i += 1; + } + } + + // + // Guess it's a valid device.. + // + + return TRUE; +} + + + + + +ULONG +HalpGetPCIData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER Slot, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ) +/*++ + +Routine Description: + + The function returns the Pci bus data for a device. + +Arguments: + + BusNumber - Indicates which bus. + + VendorSpecificDevice - The VendorID (low Word) and DeviceID (High Word) + + 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. + + If this PCI slot has never been set, then the configuration information + returned is zeroed. + + +--*/ +{ + PPCI_COMMON_CONFIG PciData; + UCHAR iBuffer[PCI_COMMON_HDR_LENGTH]; + PPCIPBUSDATA BusData; + ULONG Len; + ULONG i, bit; + + if (Length > sizeof (PCI_COMMON_CONFIG)) { + Length = sizeof (PCI_COMMON_CONFIG); + } + + Len = 0; + PciData = (PPCI_COMMON_CONFIG) iBuffer; + + if (Offset >= PCI_COMMON_HDR_LENGTH) { + // + // The user did not request any data from the common + // header. Verify the PCI device exists, then continue + // in the device specific area. + // + + HalpReadPCIConfig (BusHandler, Slot, PciData, 0, sizeof(ULONG)); + + if (PciData->VendorID == PCI_INVALID_VENDORID) { + return 0; + } + + } else { + + // + // Caller requested at least some data within the + // common header. Read the whole header, effect the + // fields we need to and then copy the user's requested + // bytes from the header + // + + BusData = (PPCIPBUSDATA) BusHandler->BusData; + + // + // Read this PCI devices slot data + // + + Len = PCI_COMMON_HDR_LENGTH; + HalpReadPCIConfig (BusHandler, Slot, PciData, 0, Len); + + if (PciData->VendorID == PCI_INVALID_VENDORID || + PCI_CONFIG_TYPE (PciData) != PCI_DEVICE_TYPE) { + PciData->VendorID = PCI_INVALID_VENDORID; + Len = 2; // only return invalid id + + } else { + + BusData->CommonData.Pin2Line (BusHandler, RootHandler, Slot, PciData); + } + + // + // Has this PCI device been configured? + // + +#if 0 + // + // On DBG build, if this PCI device has not yet been configured, + // then don't report any current configuration the device may have. + // + + bit = PciBitIndex(Slot.u.bits.DeviceNumber, Slot.u.bits.FunctionNumber); + if (!RtlCheckBit(&BusData->DeviceConfigured, bit)) { + + for (i=0; i < PCI_TYPE0_ADDRESSES; i++) { + PciData->u.type0.BaseAddresses[i] = 0; + } + + PciData->u.type0.ROMBaseAddress = 0; + PciData->Command &= ~(PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE); + } +#endif + + + // + // Copy whatever data overlaps into the callers buffer + // + + if (Len < Offset) { + // no data at caller's buffer + return 0; + } + + Len -= Offset; + if (Len > Length) { + Len = Length; + } + + RtlMoveMemory(Buffer, iBuffer + Offset, Len); + + Offset += Len; + Buffer += Len; + Length -= Len; + } + + if (Length) { + if (Offset >= PCI_COMMON_HDR_LENGTH) { + // + // The remaining Buffer comes from the Device Specific + // area - put on the kitten gloves and read from it. + // + // Specific read/writes to the PCI device specific area + // are guarenteed: + // + // Not to read/write any byte outside the area specified + // by the caller. (this may cause WORD or BYTE references + // to the area in order to read the non-dword aligned + // ends of the request) + // + // To use a WORD access if the requested length is exactly + // a WORD long. + // + // To use a BYTE access if the requested length is exactly + // a BYTE long. + // + + HalpReadPCIConfig (BusHandler, Slot, Buffer, Offset, Length); + Len += Length; + } + } + + return Len; +} + +ULONG +HalpSetPCIData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER Slot, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ) +/*++ + +Routine Description: + + The function returns the Pci bus data for a device. + +Arguments: + + + VendorSpecificDevice - The VendorID (low Word) and DeviceID (High Word) + + 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. + +--*/ +{ + PPCI_COMMON_CONFIG PciData, PciData2; + UCHAR iBuffer[PCI_COMMON_HDR_LENGTH]; + UCHAR iBuffer2[PCI_COMMON_HDR_LENGTH]; + PPCIPBUSDATA BusData; + ULONG Len, cnt; + + + if (Length > sizeof (PCI_COMMON_CONFIG)) { + Length = sizeof (PCI_COMMON_CONFIG); + } + + + Len = 0; + PciData = (PPCI_COMMON_CONFIG) iBuffer; + PciData2 = (PPCI_COMMON_CONFIG) iBuffer2; + + + if (Offset >= PCI_COMMON_HDR_LENGTH) { + // + // The user did not request any data from the common + // header. Verify the PCI device exists, then continue in + // the device specific area. + // + + HalpReadPCIConfig (BusHandler, Slot, PciData, 0, sizeof(ULONG)); + + if (PciData->VendorID == PCI_INVALID_VENDORID) { + return 0; + } + + } else { + + // + // Caller requested to set at least some data within the + // common header. + // + + Len = PCI_COMMON_HDR_LENGTH; + HalpReadPCIConfig (BusHandler, Slot, PciData, 0, Len); + if (PciData->VendorID == PCI_INVALID_VENDORID || + PCI_CONFIG_TYPE (PciData) != PCI_DEVICE_TYPE) { + + // no device, or header type unkown + return 0; + } + + + // + // Set this device as configured + // + + BusData = (PPCIPBUSDATA) BusHandler->BusData; +#if 0 + cnt = PciBitIndex(Slot.u.bits.DeviceNumber, Slot.u.bits.FunctionNumber); + RtlSetBits (&BusData->DeviceConfigured, cnt, 1); +#endif + // + // Copy COMMON_HDR values to buffer2, then overlay callers changes. + // + + RtlMoveMemory (iBuffer2, iBuffer, Len); + BusData->CommonData.Pin2Line (BusHandler, RootHandler, Slot, PciData2); + + Len -= Offset; + if (Len > Length) { + Len = Length; + } + + RtlMoveMemory (iBuffer2+Offset, Buffer, Len); + + // in case interrupt line or pin was editted + BusData->CommonData.Line2Pin (BusHandler, RootHandler, Slot, PciData2, PciData); + +#if DBG + // + // Verify R/O fields haven't changed + // + if (PciData2->VendorID != PciData->VendorID || + PciData2->DeviceID != PciData->DeviceID || + PciData2->RevisionID != PciData->RevisionID || + PciData2->ProgIf != PciData->ProgIf || + PciData2->SubClass != PciData->SubClass || + PciData2->BaseClass != PciData->BaseClass || + PciData2->HeaderType != PciData->HeaderType || + PciData2->BaseClass != PciData->BaseClass || + PciData2->u.type0.MinimumGrant != PciData->u.type0.MinimumGrant || + PciData2->u.type0.MaximumLatency != PciData->u.type0.MaximumLatency) { + DbgPrint ("PCI SetBusData: Read-Only configuration value changed\n"); + //DbgBreakPoint (); + } +#endif + // + // Set new PCI configuration + // + + HalpWritePCIConfig (BusHandler, Slot, iBuffer2+Offset, Offset, Len); + + Offset += Len; + Buffer += Len; + Length -= Len; + } + + if (Length) { + if (Offset >= PCI_COMMON_HDR_LENGTH) { + // + // The remaining Buffer comes from the Device Specific + // area - put on the kitten gloves and write it + // + // Specific read/writes to the PCI device specific area + // are guarenteed: + // + // Not to read/write any byte outside the area specified + // by the caller. (this may cause WORD or BYTE references + // to the area in order to read the non-dword aligned + // ends of the request) + // + // To use a WORD access if the requested length is exactly + // a WORD long. + // + // To use a BYTE access if the requested length is exactly + // a BYTE long. + // + + HalpWritePCIConfig (BusHandler, Slot, Buffer, Offset, Length); + Len += Length; + } + } + + return Len; +} + +VOID +HalpReadPCIConfig ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ) +{ +#define ATIBUG 1 +#if ATIBUG + USHORT VendorId; + LONG Len; +#endif + + if (!HalpValidPCISlot (BusHandler, Slot)) { + // + // Invalid SlotID return no data + // + + RtlFillMemory (Buffer, Length, (UCHAR) -1); + return ; + } + +#if ATIBUG +// +// Temporary Hack (MOTKJR) - We have discovered a problem between the ATI +// Video Driver and the NCR 810/825 SCSI parts. The NCR chip has hardware +// registers in Configuration Space above 0x40 which have a side effect that +// a read from these registers is destructive to its contents. If a SCSI +// operation is active when these registers are read, the NCR device will +// abort the operation and further I/O is impossible. Therefore, we will +// not allow anyone to read from Offset 0x40 to 0xFF for any PCI slot that +// has an NCR vendor ID number. Care must be taken to check for requests +// which overlap both the PCI Common Header and the Device Dependent area. +// +#define NCR_VENDOR_ID 0x1000 + + HalpPCIConfig (BusHandler, Slot, (PUCHAR) &VendorId, 0x0, sizeof(VendorId), + PCIConfigHandler.ConfigRead); + + if ((VendorId == NCR_VENDOR_ID) && (Offset + Length > PCI_COMMON_HDR_LENGTH)) { + Len = PCI_COMMON_HDR_LENGTH - Offset; + if (Len < 0) + Len = 0; + RtlFillMemory ((PVOID)((PUCHAR)Buffer+Len), Length-Len, (UCHAR) -1); + if (Offset >= PCI_COMMON_HDR_LENGTH) + return; + Length = Len; + } +#endif + + HalpPCIConfig (BusHandler, Slot, (PUCHAR) Buffer, Offset, Length, + PCIConfigHandler.ConfigRead); +} + +VOID +HalpWritePCIConfig ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ) +{ + if (!HalpValidPCISlot (BusHandler, Slot)) { + // + // Invalid SlotID do nothing + // + return ; + } + + HalpPCIConfig (BusHandler, Slot, (PUCHAR) Buffer, Offset, Length, + PCIConfigHandler.ConfigWrite); +} + +BOOLEAN +HalpValidPCISlot ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot + ) +{ + PCI_SLOT_NUMBER Slot2; + PPCIPBUSDATA BusData; + UCHAR HeaderType; + ULONG i; + + BusData = (PPCIPBUSDATA) BusHandler->BusData; + + if (Slot.u.bits.Reserved != 0) { + return FALSE; + } + + if (Slot.u.bits.DeviceNumber >= BusData->MaxDevice) { + return FALSE; + } + + if (Slot.u.bits.FunctionNumber == 0) { + return TRUE; + } + + // + // Non zero function numbers are only supported if the + // device has the PCI_MULTIFUNCTION bit set in it's header + // + + i = Slot.u.bits.DeviceNumber; + + // + // Read DeviceNumber, Function zero, to determine if the + // PCI supports multifunction devices + // + + Slot2 = Slot; + Slot2.u.bits.FunctionNumber = 0; + + HalpReadPCIConfig ( + BusHandler, + Slot2, + &HeaderType, + FIELD_OFFSET (PCI_COMMON_CONFIG, HeaderType), + sizeof (UCHAR) + ); + + if (!(HeaderType & PCI_MULTIFUNCTION) || HeaderType == 0xFF) { + // this device doesn't exists or doesn't support MULTIFUNCTION types + return FALSE; + } + + return TRUE; +} + + +VOID +HalpPCIConfig ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length, + IN FncConfigIO *ConfigIO + ) +{ + KIRQL OldIrql; + ULONG i; + UCHAR State[20]; + PPCIPBUSDATA BusData; + + BusData = (PPCIPBUSDATA) BusHandler->BusData; + PCIConfigHandler.Synchronize (BusHandler, Slot, &OldIrql, State); + + while (Length) { + i = PCIDeref[Offset % sizeof(ULONG)][Length % sizeof(ULONG)]; + i = ConfigIO[i] (BusData, State, Buffer, Offset); + + Offset += i; + Buffer += i; + Length -= i; + } + + PCIConfigHandler.ReleaseSynchronzation (BusHandler, OldIrql); +} + +VOID HalpPCISynchronizeType1 ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PKIRQL Irql, + IN PPCI_TYPE1_CFG_BITS PciCfg1 + ) +{ + // + // Initialize PciCfg1 + // + + PciCfg1->u.AsULONG = HalpTranslatePciSlotNumber(BusHandler->BusNumber, Slot.u.bits.DeviceNumber) + + 0x100 * Slot.u.bits.FunctionNumber; + +} + +VOID HalpPCIReleaseSynchronzationType1 ( + IN PBUS_HANDLER BusHandler, + IN KIRQL Irql + ) +{ + + +} + + +ULONG +HalpPCIReadUcharType1 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG i; + + i = Offset % sizeof(ULONG); + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + + *Buffer = READ_PORT_UCHAR ((PUCHAR)(PciCfg1->u.AsULONG + i)); + return sizeof (UCHAR); +} + +ULONG +HalpPCIReadUshortType1 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG i; + + i = Offset % sizeof(ULONG); + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + + *((PUSHORT) Buffer) = READ_PORT_USHORT ((PUSHORT)(PciCfg1->u.AsULONG + i)); + return sizeof (USHORT); +} + +ULONG +HalpPCIReadUlongType1 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + + *((PULONG) Buffer) = READ_PORT_ULONG ((PULONG) (PciCfg1->u.AsULONG)); + return sizeof (ULONG); +} + + +ULONG +HalpPCIWriteUcharType1 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG i; + + i = Offset % sizeof(ULONG); + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + + WRITE_PORT_UCHAR (PciCfg1->u.AsULONG + i, *Buffer ); + return sizeof (UCHAR); +} + +ULONG +HalpPCIWriteUshortType1 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG i; + + i = Offset % sizeof(ULONG); + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + + WRITE_PORT_USHORT (PciCfg1->u.AsULONG + i, *((PUSHORT) Buffer) ); + return sizeof (USHORT); +} + +ULONG +HalpPCIWriteUlongType1 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + + WRITE_PORT_ULONG (PciCfg1->u.AsULONG, *((PULONG) Buffer) ); + return sizeof (ULONG); +} + +VOID HalpPCISynchronizeType2 ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PKIRQL Irql, + IN PPCI_TYPE1_CFG_BITS PciCfg1 + ) +{ + + // + // Initialize PciCfg1 + // + + PciCfg1->u.AsULONG = 0; + if ((PciCfg1->u.bits.BusNumber = BusHandler->BusNumber) == 0) { + + // This hack is to maintain device number compatibility + // on bus 0 with the Type1 functions. We do this so that + // the installed base maintains the same "slot" numbering. + // The notable issue is with network interfaces where the + // slot number is stored in the registry at install time. + // It was judged too subtle and too painful to have everyone + // reinstall networking if they added a bridged device to + // their system. + + int MappedDev; + ULONG Offset; + #define PRESHIFT 8 // Make invalid slot numbers to map to dev 9. + // Dev 9 is inaccessible from the eagle. + + // Get the offset from the Type1 (direct mapping) offset table. + // If the device number isn't "valid", use an offset that won't + // actually end up selecting any device. + + Offset = (Slot.u.bits.DeviceNumber < HalpPciMaxSlots) ? + HalpPciConfigSlot[Slot.u.bits.DeviceNumber] : (1 << PRESHIFT); + + // Determine the device number accessed by the "offset". + // If bit 11 is set, MappedDev = 11; bit 12, MappedDev = 12;... + + Offset >>= PRESHIFT; + MappedDev = PRESHIFT - 1; + + do { + MappedDev++; + Offset >>= 1; + + } while (Offset); + + // The eagle docs say to set the device number field to 10 + // for PCI device 31. + + PciCfg1->u.bits.DeviceNumber = (MappedDev == 31) ? 10 : MappedDev; + + } else { + PciCfg1->u.bits.DeviceNumber = Slot.u.bits.DeviceNumber; + } + PciCfg1->u.bits.FunctionNumber = Slot.u.bits.FunctionNumber; + PciCfg1->u.bits.Enable = TRUE; + + KeRaiseIrql (PROFILE_LEVEL, Irql); + KiAcquireSpinLock (&HalpPCIConfigLock); + +} + + +VOID HalpPCIReleaseSynchronzationType2 ( + IN PBUS_HANDLER BusHandler, + IN KIRQL Irql + ) +{ + + KiReleaseSpinLock (&HalpPCIConfigLock); + KeLowerIrql (Irql); + +} + + +ULONG +HalpPCIReadUcharType2 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG i; + + i = Offset % sizeof(ULONG); + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + + WRITE_PORT_ULONG (&((PPLANAR_CONTROL)HalpIoControlBase)->ConfigAddress, PciCfg1->u.AsULONG ); + *((PUCHAR) Buffer) = READ_PORT_UCHAR ((PUCHAR)&((PPLANAR_CONTROL)HalpIoControlBase)->ConfigData + i); + return sizeof (UCHAR); +} + +ULONG +HalpPCIReadUshortType2 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG i; + + i = Offset % sizeof(ULONG); + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + + WRITE_PORT_ULONG (&((PPLANAR_CONTROL)HalpIoControlBase)->ConfigAddress, PciCfg1->u.AsULONG ); + *((PUSHORT) Buffer) = READ_PORT_USHORT ((PUCHAR)&((PPLANAR_CONTROL)HalpIoControlBase)->ConfigData + i); + return sizeof (USHORT); +} + +ULONG +HalpPCIReadUlongType2 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + + WRITE_PORT_ULONG (&((PPLANAR_CONTROL)HalpIoControlBase)->ConfigAddress, PciCfg1->u.AsULONG); + *((PULONG) Buffer) = READ_PORT_ULONG (&((PPLANAR_CONTROL)HalpIoControlBase)->ConfigData); + return sizeof(ULONG); +} + + +ULONG +HalpPCIWriteUcharType2 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG i; + + i = Offset % sizeof(ULONG); + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + + WRITE_PORT_ULONG (&((PPLANAR_CONTROL)HalpIoControlBase)->ConfigAddress, PciCfg1->u.AsULONG ); + WRITE_PORT_UCHAR ((PUCHAR)&((PPLANAR_CONTROL)HalpIoControlBase)->ConfigData + i,*Buffer); + return sizeof (UCHAR); +} + +ULONG +HalpPCIWriteUshortType2 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG i; + + i = Offset % sizeof(ULONG); + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + + WRITE_PORT_ULONG (&((PPLANAR_CONTROL)HalpIoControlBase)->ConfigAddress, PciCfg1->u.AsULONG ); + WRITE_PORT_USHORT ((PUCHAR)&((PPLANAR_CONTROL)HalpIoControlBase)->ConfigData + (USHORT) i,*((PUSHORT)Buffer)); + return sizeof (USHORT); +} + +ULONG +HalpPCIWriteUlongType2 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + + WRITE_PORT_ULONG (&((PPLANAR_CONTROL)HalpIoControlBase)->ConfigAddress, PciCfg1->u.AsULONG); + WRITE_PORT_ULONG (&((PPLANAR_CONTROL)HalpIoControlBase)->ConfigData,*((PULONG)Buffer)); + return sizeof(ULONG); +} + + +NTSTATUS +HalpAssignPCISlotResources ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PUNICODE_STRING RegistryPath, + IN PUNICODE_STRING DriverClassName OPTIONAL, + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT DeviceObject OPTIONAL, + IN ULONG Slot, + IN OUT PCM_RESOURCE_LIST *pAllocatedResources + ) +/*++ + +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: + +Return Value: + + STATUS_SUCCESS or error + +--*/ +{ + NTSTATUS status; + PUCHAR WorkingPool; + PPCI_COMMON_CONFIG PciData, PciOrigData, PciData2; + PCI_SLOT_NUMBER PciSlot; + PPCIPBUSDATA BusData; + PIO_RESOURCE_REQUIREMENTS_LIST CompleteList; + PIO_RESOURCE_DESCRIPTOR Descriptor; + PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor; + ULONG BusNumber; + ULONG i, j, m, length, memtype; + ULONG NoBaseAddress, RomIndex, Option; + PULONG BaseAddress[PCI_TYPE0_ADDRESSES + 1]; + PULONG OrigAddress[PCI_TYPE0_ADDRESSES + 1]; + BOOLEAN Match, EnableRomBase; + + + *pAllocatedResources = NULL; + PciSlot = *((PPCI_SLOT_NUMBER) &Slot); + BusNumber = BusHandler->BusNumber; + BusData = (PPCIPBUSDATA) BusHandler->BusData; + + // + // Allocate some pool for working space + // + + i = sizeof (IO_RESOURCE_REQUIREMENTS_LIST) + + sizeof (IO_RESOURCE_DESCRIPTOR) * (PCI_TYPE0_ADDRESSES + 2) * 2 + + PCI_COMMON_HDR_LENGTH * 3; + + WorkingPool = (PUCHAR) ExAllocatePool (PagedPool, i); + if (!WorkingPool) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // Zero initialize pool, and get pointers into memory + // + + RtlZeroMemory (WorkingPool, i); + CompleteList = (PIO_RESOURCE_REQUIREMENTS_LIST) WorkingPool; + PciData = (PPCI_COMMON_CONFIG) (WorkingPool + i - PCI_COMMON_HDR_LENGTH * 3); + PciData2 = (PPCI_COMMON_CONFIG) (WorkingPool + i - PCI_COMMON_HDR_LENGTH * 2); + PciOrigData = (PPCI_COMMON_CONFIG) (WorkingPool + i - PCI_COMMON_HDR_LENGTH * 1); + + // + // Read the PCI device's configuration + // + + HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH); + if (PciData->VendorID == PCI_INVALID_VENDORID) { + ExFreePool (WorkingPool); + return STATUS_NO_SUCH_DEVICE; + } + + // + // Make a copy of the device's current settings + // + + RtlMoveMemory (PciOrigData, PciData, PCI_COMMON_HDR_LENGTH); + + // + // Initialize base addresses base on configuration data type + // + + switch (PCI_CONFIG_TYPE(PciData)) { + case 0 : + NoBaseAddress = PCI_TYPE0_ADDRESSES+1; + for (j=0; j < PCI_TYPE0_ADDRESSES; j++) { + BaseAddress[j] = &PciData->u.type0.BaseAddresses[j]; + OrigAddress[j] = &PciOrigData->u.type0.BaseAddresses[j]; + } + BaseAddress[j] = &PciData->u.type0.ROMBaseAddress; + OrigAddress[j] = &PciOrigData->u.type0.ROMBaseAddress; + RomIndex = j; + break; + case 1: + NoBaseAddress = PCI_TYPE1_ADDRESSES+1; + for (j=0; j < PCI_TYPE1_ADDRESSES; j++) { + BaseAddress[j] = &PciData->u.type1.BaseAddresses[j]; + OrigAddress[j] = &PciOrigData->u.type1.BaseAddresses[j]; + } + BaseAddress[j] = &PciData->u.type1.ROMBaseAddress; + OrigAddress[j] = &PciOrigData->u.type1.ROMBaseAddress; + RomIndex = j; + break; + + default: + ExFreePool (WorkingPool); + return STATUS_NO_SUCH_DEVICE; + } + + // + // If the BIOS doesn't have the device's ROM enabled, then we won't + // enable it either. Remove it from the list. + // + + EnableRomBase = TRUE; + if (!(*BaseAddress[RomIndex] & PCI_ROMADDRESS_ENABLED)) { + ASSERT (RomIndex+1 == NoBaseAddress); + EnableRomBase = FALSE; + NoBaseAddress -= 1; + } + + // + // Set resources to all bits on to see what type of resources + // are required. + // + + for (j=0; j < NoBaseAddress; j++) { + *BaseAddress[j] = 0xFFFFFFFF; + } + +//*BJ* PciData->Command &= ~(PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE); + *BaseAddress[RomIndex] &= ~PCI_ROMADDRESS_ENABLED; + HalpWritePCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH); + HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH); + + // note type0 & type1 overlay ROMBaseAddress, InterruptPin, and InterruptLine + BusData->CommonData.Pin2Line (BusHandler, RootHandler, PciSlot, PciData); + + // + // Build an IO_RESOURCE_REQUIREMENTS_LIST for the PCI device + // + + CompleteList->InterfaceType = PCIBus; + CompleteList->BusNumber = BusNumber; + CompleteList->SlotNumber = Slot; + CompleteList->AlternativeLists = 1; + + CompleteList->List[0].Version = 1; + CompleteList->List[0].Revision = 1; + + Descriptor = CompleteList->List[0].Descriptors; + + // + // If PCI device has an interrupt resource, add it + // + + if (PciData->u.type0.InterruptPin) { + CompleteList->List[0].Count++; + + Descriptor->Option = 0; + Descriptor->Type = CmResourceTypeInterrupt; + Descriptor->ShareDisposition = CmResourceShareShared; + Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; + + // Fill in any vector here - we'll pick it back up in + // HalAdjustResourceList and adjust it to it's allowed settings + Descriptor->u.Interrupt.MinimumVector = 0; + Descriptor->u.Interrupt.MaximumVector = 0xff; + Descriptor++; + } + + // + // Add a memory/port resoruce for each PCI resource + // + + *BaseAddress[RomIndex] &= ~0x7ff; + + // + // Rom Base Address resource is not enabled, as the ROM code cannot + // be executed on a risk box, and the algorithm below interprets + // the card's Rom Base Address requirements incorrectly + // + + + for (j=0; j < NoBaseAddress; j++) { + if (*BaseAddress[j]) { + i = *BaseAddress[j]; + + // scan for first set bit, that's the length & alignment + length = 1 << (i & PCI_ADDRESS_IO_SPACE ? 2 : 4); + while (!(i & length) && length) { + length <<= 1; + } + + // scan for last set bit, that's the maxaddress + 1 + for (m = length; i & m; m <<= 1) ; + m--; + + // check for hosed PCI configuration requirements + if (length & ~m) { +#if DBG + DbgPrint ("PCI: defective device! Bus %d, Slot %d, Function %d\n", + BusNumber, + PciSlot.u.bits.DeviceNumber, + PciSlot.u.bits.FunctionNumber + ); + + DbgPrint ("PCI: BaseAddress[%d] = %08lx\n", j, i); +#endif + // the device is in error - punt. don't allow this + // resource any option - it either gets set to whatever + // bits it was able to return, or it doesn't get set. + + if (i & PCI_ADDRESS_IO_SPACE) { + m = i & ~0x3; + Descriptor->u.Port.MinimumAddress.LowPart = m; + } else { + m = i & ~0xf; + Descriptor->u.Memory.MinimumAddress.LowPart = m; + } + + m += length; // max address is min address + length + } + + // + // Add requested resource + // + + Descriptor->Option = 0; + if (i & PCI_ADDRESS_IO_SPACE) { + memtype = 0; + + if (PciOrigData->Command & PCI_ENABLE_IO_SPACE) { + + // + // The IO range is/was already enabled at some location, add that + // as it's preferred setting. + // + + Descriptor->Type = CmResourceTypePort; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + Descriptor->Flags = CM_RESOURCE_PORT_IO; + Descriptor->Option = IO_RESOURCE_PREFERRED; + + Descriptor->u.Port.Length = length; + Descriptor->u.Port.Alignment = length; + Descriptor->u.Port.MinimumAddress.LowPart = *OrigAddress[j] & ~0x3; + Descriptor->u.Port.MaximumAddress.LowPart = + Descriptor->u.Port.MinimumAddress.LowPart + length - 1; + + CompleteList->List[0].Count++; + Descriptor++; + + Descriptor->Option = IO_RESOURCE_ALTERNATIVE; + } + + // + // Add this IO range + // + + Descriptor->Type = CmResourceTypePort; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + Descriptor->Flags = CM_RESOURCE_PORT_IO; + + Descriptor->u.Port.Length = length; + Descriptor->u.Port.Alignment = length; + Descriptor->u.Port.MaximumAddress.LowPart = m; + + } else { + + memtype = i & PCI_ADDRESS_MEMORY_TYPE_MASK; + + Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE; + if (j == RomIndex) { + // this is a ROM address + Descriptor->Flags = CM_RESOURCE_MEMORY_READ_ONLY; + } + + if (i & PCI_ADDRESS_MEMORY_PREFETCHABLE) { + Descriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; + } + + if (!Is64BitBaseAddress(i) && + (j == RomIndex || + PciOrigData->Command & PCI_ENABLE_MEMORY_SPACE)) { + + // + // The memory range is/was already enabled at some location, add that + // as it's preferred setting. + // + + Descriptor->Type = CmResourceTypeMemory; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + Descriptor->Option = IO_RESOURCE_PREFERRED; + + Descriptor->u.Port.Length = length; + Descriptor->u.Port.Alignment = length; + Descriptor->u.Port.MinimumAddress.LowPart = *OrigAddress[j] & ~0xF; + Descriptor->u.Port.MaximumAddress.LowPart = + Descriptor->u.Port.MinimumAddress.LowPart + length - 1; + + CompleteList->List[0].Count++; + Descriptor++; + + Descriptor->Flags = Descriptor[-1].Flags; + Descriptor->Option = IO_RESOURCE_ALTERNATIVE; + } + + // + // Add this memory range + // + + Descriptor->Type = CmResourceTypeMemory; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + + Descriptor->u.Memory.Length = length; + Descriptor->u.Memory.Alignment = length; + Descriptor->u.Memory.MaximumAddress.LowPart = m; + + if (memtype == PCI_TYPE_20BIT && m > 0xFFFFF) { + // limit to 20 bit address + Descriptor->u.Memory.MaximumAddress.LowPart = 0xFFFFF; + } + + if (Is64BitBaseAddress(i)) { + // skip upper half of 64 bit address since this processor + // only supports 32 bits of address space + j++; + } + } + + CompleteList->List[0].Count++; + Descriptor++; + + } + } + + CompleteList->ListSize = (ULONG) + ((PUCHAR) Descriptor - (PUCHAR) CompleteList); + + // + // Restore the device settings as we found them, enable memory + // and io decode after setting base addresses. This is done in + // case HalAdjustResourceList wants to read the current settings + // in the device. + // + + HalpWritePCIConfig ( + BusHandler, + PciSlot, + &PciOrigData->Status, + FIELD_OFFSET (PCI_COMMON_CONFIG, Status), + PCI_COMMON_HDR_LENGTH - FIELD_OFFSET (PCI_COMMON_CONFIG, Status) + ); + + HalpWritePCIConfig ( + BusHandler, + PciSlot, + PciOrigData, + 0, + FIELD_OFFSET (PCI_COMMON_CONFIG, Status) + ); + + // + // Have the IO system allocate resource assignments + // + + status = IoAssignResources ( + RegistryPath, + DriverClassName, + DriverObject, + DeviceObject, + CompleteList, + pAllocatedResources + ); + + if (!NT_SUCCESS(status)) { + goto CleanUp; + } + + // + // Slurp the assigments back into the PciData structure and + // perform them + // + + CmDescriptor = (*pAllocatedResources)->List[0].PartialResourceList.PartialDescriptors; + + // + // If PCI device has an interrupt resource then that was + // passed in as the first requested resource + // + + if (PciData->u.type0.InterruptPin) { + PciData->u.type0.InterruptLine = (UCHAR) CmDescriptor->u.Interrupt.Vector; + BusData->CommonData.Line2Pin (BusHandler, RootHandler, PciSlot, PciData, PciOrigData); + CmDescriptor++; + } + + // + // Pull out resources in the order they were passed to IoAssignResources + // + + m = 0; + for (j=0; j < NoBaseAddress; j++) { + i = *BaseAddress[j]; + if (i) { + if (i & PCI_ADDRESS_IO_SPACE) { + m |= PCI_ENABLE_IO_SPACE; + *BaseAddress[j] = CmDescriptor->u.Port.Start.LowPart; + } else { + m |= PCI_ENABLE_MEMORY_SPACE; + *BaseAddress[j] = CmDescriptor->u.Memory.Start.LowPart; + + if (Is64BitBaseAddress(i)) { + // skip upper 32 bits + j++; + } + } + CmDescriptor++; + } + } + + // + // Set addresses, but do not turn on decodes + // + + HalpWritePCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH); + + // + // Read configuration back and verify address settings took + // + + HalpReadPCIConfig(BusHandler, PciSlot, PciData2, 0, PCI_COMMON_HDR_LENGTH); + + Match = TRUE; + if (PciData->u.type0.InterruptLine != PciData2->u.type0.InterruptLine || + PciData->u.type0.InterruptPin != PciData2->u.type0.InterruptPin || + PciData->u.type0.ROMBaseAddress != PciData2->u.type0.ROMBaseAddress) { + Match = FALSE; + } + + for (j=0; j < NoBaseAddress; j++) { + if (*BaseAddress[j]) { + if (*BaseAddress[j] & PCI_ADDRESS_IO_SPACE) { + i = (ULONG) ~0x3; + } else { + i = (ULONG) ~0xF; + } + + if ((*BaseAddress[j] & i) != + *((PULONG) ((PUCHAR) BaseAddress[j] - + (PUCHAR) PciData + + (PUCHAR) PciData2)) & i) { + + Match = FALSE; + } + + if (!(*BaseAddress[j] & PCI_ADDRESS_IO_SPACE) && + (Is64BitBaseAddress(*BaseAddress[j]))) { + // skip upper 32 bits + j++; + } + } + } + + if (!Match) { +#if DBG + DbgPrint ("PCI: defective device! Bus %d, Slot %d, Function %d\n", + BusNumber, + PciSlot.u.bits.DeviceNumber, + PciSlot.u.bits.FunctionNumber + ); +#endif + status = STATUS_DEVICE_PROTOCOL_ERROR; + goto CleanUp; + } + + // + // Settings took - turn on the appropiate decodes + // + + if (EnableRomBase && *BaseAddress[RomIndex]) { + // a rom address was allocated and should be enabled + *BaseAddress[RomIndex] |= PCI_ROMADDRESS_ENABLED; + HalpWritePCIConfig ( + BusHandler, + PciSlot, + BaseAddress[RomIndex], + (ULONG) ((PUCHAR) BaseAddress[RomIndex] - (PUCHAR) PciData), + sizeof (ULONG) + ); + } + + // enable IO & Memory decodes (use HalSetBusData since valid settings now set) + + // Set Bus master bit on for win95 compatability + m |= PCI_ENABLE_BUS_MASTER; + + PciData->Command |= (USHORT) m; + HalSetBusDataByOffset ( + PCIConfiguration, + BusHandler->BusNumber, + PciSlot.u.AsULONG, + &PciData->Command, + FIELD_OFFSET (PCI_COMMON_CONFIG, Command), + sizeof (PciData->Command) + ); + +CleanUp: + if (!NT_SUCCESS(status)) { + + // + // Failure, if there are any allocated resources free them + // + + if (*pAllocatedResources) { + IoAssignResources ( + RegistryPath, + DriverClassName, + DriverObject, + DeviceObject, + NULL, + NULL + ); + + ExFreePool (*pAllocatedResources); + *pAllocatedResources = NULL; + } + + // + // Restore the device settings as we found them, enable memory + // and io decode after setting base addresses + // + + HalpWritePCIConfig ( + BusHandler, + PciSlot, + &PciOrigData->Status, + FIELD_OFFSET (PCI_COMMON_CONFIG, Status), + PCI_COMMON_HDR_LENGTH - FIELD_OFFSET (PCI_COMMON_CONFIG, Status) + ); + + HalpWritePCIConfig ( + BusHandler, + PciSlot, + PciOrigData, + 0, + FIELD_OFFSET (PCI_COMMON_CONFIG, Status) + ); + } + + ExFreePool (WorkingPool); + return status; +} + +#if DBG +VOID +HalpTestPci (ULONG flag2) +{ + PCI_SLOT_NUMBER SlotNumber; + PCI_COMMON_CONFIG PciData, OrigData; + ULONG i, f, j, k, bus; + BOOLEAN flag; + + + if (!flag2) { + return ; + } + + DbgBreakPoint (); + SlotNumber.u.bits.Reserved = 0; + + // + // Read every possible PCI Device/Function and display it's + // default info. + // + // (note this destories it's current settings) + // + + flag = TRUE; + for (bus = 0; flag; bus++) { + + for (i = 0; i < PCI_MAX_DEVICES; i++) { + SlotNumber.u.bits.DeviceNumber = i; + + for (f = 0; f < PCI_MAX_FUNCTION; f++) { + SlotNumber.u.bits.FunctionNumber = f; + + // + // Note: This is reading the DeviceSpecific area of + // the device's configuration - normally this should + // only be done on device for which the caller understands. + // I'm doing it here only for debugging. + // + + j = HalGetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); + + if (j == 0) { + // out of buses + flag = FALSE; + break; + } + + if (j < PCI_COMMON_HDR_LENGTH) { + continue; + } + + HalSetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + 1 + ); + + HalGetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); + +#if 0 + memcpy (&OrigData, &PciData, sizeof PciData); + + for (j=0; j < PCI_TYPE0_ADDRESSES; j++) { + PciData.u.type0.BaseAddresses[j] = 0xFFFFFFFF; + } + + PciData.u.type0.ROMBaseAddress = 0xFFFFFFFF; + + HalSetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); + + HalGetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); +#endif + + DbgPrint ("PCI Bus %d Slot %2d %2d ID:%04lx-%04lx Rev:%04lx", + bus, i, f, PciData.VendorID, PciData.DeviceID, + PciData.RevisionID); + + + if (PciData.u.type0.InterruptPin) { + DbgPrint (" IntPin:%x", PciData.u.type0.InterruptPin); + } + + if (PciData.u.type0.InterruptLine) { + DbgPrint (" IntLine:%x", PciData.u.type0.InterruptLine); + } + + if (PciData.u.type0.ROMBaseAddress) { + DbgPrint (" ROM:%08lx", PciData.u.type0.ROMBaseAddress); + } + + DbgPrint ("\n Cmd:%04x Status:%04x ProgIf:%04x SubClass:%04x BaseClass:%04lx\n", + PciData.Command, PciData.Status, PciData.ProgIf, + PciData.SubClass, PciData.BaseClass); + + k = 0; + for (j=0; j < PCI_TYPE0_ADDRESSES; j++) { + if (PciData.u.type0.BaseAddresses[j]) { + DbgPrint (" Ad%d:%08lx", j, PciData.u.type0.BaseAddresses[j]); + k = 1; + } + } + +#if 0 + if (PciData.u.type0.ROMBaseAddress == 0xC08001) { + + PciData.u.type0.ROMBaseAddress = 0xC00001; + HalSetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); + + HalGetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); + + DbgPrint ("\n Bogus rom address, edit yields:%08lx", + PciData.u.type0.ROMBaseAddress); + } +#endif + + if (k) { + DbgPrint ("\n"); + } + + if (PciData.VendorID == 0x8086) { + // dump complete buffer + DbgPrint ("Command %x, Status %x, BIST %x\n", + PciData.Command, PciData.Status, + PciData.BIST + ); + + DbgPrint ("CacheLineSz %x, LatencyTimer %x", + PciData.CacheLineSize, PciData.LatencyTimer + ); + + for (j=0; j < 192; j++) { + if ((j & 0xf) == 0) { + DbgPrint ("\n%02x: ", j + 0x40); + } + DbgPrint ("%02x ", PciData.DeviceSpecific[j]); + } + DbgPrint ("\n"); + } + + +#if 0 + // + // now print original data + // + + if (OrigData.u.type0.ROMBaseAddress) { + DbgPrint (" oROM:%08lx", OrigData.u.type0.ROMBaseAddress); + } + + DbgPrint ("\n"); + k = 0; + for (j=0; j < PCI_TYPE0_ADDRESSES; j++) { + if (OrigData.u.type0.BaseAddresses[j]) { + DbgPrint (" oAd%d:%08lx", j, OrigData.u.type0.BaseAddresses[j]); + k = 1; + } + } + + // + // Restore original settings + // + + HalSetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &OrigData, + sizeof (PciData) + ); +#endif + + // + // Next + // + + if (k) { + DbgPrint ("\n\n"); + } + } + } + } + DbgBreakPoint (); +} +#endif diff --git a/private/ntos/nthals/haleagle/ppc/pxpciint.c b/private/ntos/nthals/haleagle/ppc/pxpciint.c new file mode 100644 index 000000000..36c139b3f --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxpciint.c @@ -0,0 +1,221 @@ +/*++ + + +Copyright (C) 1989-1995 Microsoft Corporation + +Module Name: + + pxpciint.c + +Abstract: + + All PCI bus interrupt mapping is in this module, so that a real + system which doesn't have all the limitations which PC PCI + systems have can replaced this code easly. + (bus memory & i/o address mappings can also be fix here) + +Author: + + Ken Reneris + Jim Wooldridge - Ported to PowerPC + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#include "halp.h" +#include "pci.h" +#include "pcip.h" + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE,HalpGetPCIIntOnISABus) +#pragma alloc_text(PAGE,HalpAdjustPCIResourceList) +#pragma alloc_text(PAGE,HalpGetISAFixedPCIIrq) +#endif + + +ULONG +HalpGetPCIIntOnISABus ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ) +{ + if (BusInterruptLevel < 1) { + // bogus bus level + return 0; + } + + + // + // Current PCI buses just map their IRQs ontop of the ISA space, + // so foreward this to the isa handler for the isa vector + // (the isa vector was saved away at either HalSetBusData or + // IoAssignReosurces time - if someone is trying to connect a + // PCI interrupt without performing one of those operations first, + // they are broken). + // + + return HalGetInterruptVector ( + Internal, 0, + BusInterruptLevel, + BusInterruptVector, + Irql, + Affinity + ); +} + + +VOID +HalpPCIPin2ISALine ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER SlotNumber, + IN PPCI_COMMON_CONFIG PciData + ) +/*++ + + This function maps the device's InterruptPin to an InterruptLine + value. + + On the current PC implementations, the bios has already filled in + InterruptLine as it's ISA value and there's no portable way to + change it. + + +--*/ +{ +} + + + +VOID +HalpPCIISALine2Pin ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER SlotNumber, + IN PPCI_COMMON_CONFIG PciNewData, + IN PPCI_COMMON_CONFIG PciOldData + ) +/*++ + + This functions maps the device's InterruptLine to it's + device specific InterruptPin value. + + On the current PC implementations, this information is + fixed by the BIOS. Just make sure the value isn't being + editted since PCI doesn't tell us how to dynically + connect the interrupt. + +--*/ +{ +} + + +NTSTATUS +HalpAdjustPCIResourceList ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList + ) +/*++ + Rewrite the callers requested resource list to fit within + the supported ranges of this bus +--*/ +{ + NTSTATUS Status; + PPCIPBUSDATA BusData; + PCI_SLOT_NUMBER PciSlot; + PSUPPORTED_RANGE Interrupt; + + BusData = (PPCIPBUSDATA) BusHandler->BusData; + PciSlot = *((PPCI_SLOT_NUMBER) &(*pResourceList)->SlotNumber); + + // + // Determine PCI device's interrupt restrictions + // + + Status = BusData->GetIrqRange(BusHandler, RootHandler, PciSlot, &Interrupt); + + if (!NT_SUCCESS(Status)) { + return Status; + } + + // + // Adjust resources + // + + Status = HaliAdjustResourceListRange ( + BusHandler->BusAddresses, + Interrupt, + pResourceList + ); + + ExFreePool (Interrupt); + return Status; +} + + +NTSTATUS +HalpGetISAFixedPCIIrq ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER PciSlot, + OUT PSUPPORTED_RANGE *Interrupt + ) +{ + UCHAR buffer[PCI_COMMON_HDR_LENGTH]; + PPCI_COMMON_CONFIG PciData; + + + PciData = (PPCI_COMMON_CONFIG) buffer; + HalGetBusData ( + PCIConfiguration, + BusHandler->BusNumber, + PciSlot.u.AsULONG, + PciData, + PCI_COMMON_HDR_LENGTH + ); + + if (PciData->VendorID == PCI_INVALID_VENDORID || + PCI_CONFIG_TYPE (PciData) != 0) { + return STATUS_UNSUCCESSFUL; + } + + *Interrupt = ExAllocatePool (PagedPool, sizeof (SUPPORTED_RANGE)); + if (!*Interrupt) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory (*Interrupt, sizeof (SUPPORTED_RANGE)); + (*Interrupt)->Base = 1; // base = 1, limit = 0 + + if (!PciData->u.type0.InterruptPin) { + return STATUS_SUCCESS; + } + + if (PciData->u.type0.InterruptLine == 0) { +#if DBG + DbgPrint ("HalpGetValidPCIFixedIrq: BIOS did not assign an interrupt vector for the device\n"); +#endif + // + // We need to let the caller continue, since the caller may + // not care that the interrupt vector is connected or not + // + + return STATUS_SUCCESS; + } + + (*Interrupt)->Base = PciData->u.type0.InterruptLine; + (*Interrupt)->Limit = PciData->u.type0.InterruptLine; + return STATUS_SUCCESS; +} diff --git a/private/ntos/nthals/haleagle/ppc/pxpcisup.c b/private/ntos/nthals/haleagle/ppc/pxpcisup.c new file mode 100644 index 000000000..272a16022 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxpcisup.c @@ -0,0 +1,235 @@ + + +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +contains copyrighted material. Use of this file is restricted +by the provisions of a Motorola Software License Agreement. + +Module Name: + + pxpcisup.c + +Abstract: + + The module initializes any planar registers. + This module also implements machince check parity error handling. + +Author: + + Jim Wooldridge (jimw@austin.vnet.ibm.com) + + +Revision History: + + T. White -- Added dword I/O to allow GXT150P to work correctly + +Special Note: + + Please make sure that the dword I/O mechanisms are carried + forward for any box which is to support the GXT150P graphics + adapter. The GXT150P graphics adapter runs in any PowerPC + machine with a standard PCI bus connector. + + +--*/ + +#include "halp.h" +#include "pci.h" +#include "pcip.h" +#include "pxpcisup.h" + +extern PVOID HalpPciConfigBase; + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT,HalpPhase0SetPciDataByOffset) +#pragma alloc_text(INIT,HalpPhase0GetPciDataByOffset) +#endif + +ULONG HalpPciConfigSlot[] = { 0x0800, + 0x1000, + 0x2000, + 0x4000, + 0x8000, + 0x10000, + 0x20000, + 0x40000, + 0x80000 + }; + +ULONG HalpPciMaxSlots = sizeof(HalpPciConfigSlot)/sizeof(ULONG); +ULONG HalpPciConfigSize; + + +ULONG +HalpTranslatePciSlotNumber ( + ULONG BusNumber, + ULONG SlotNumber + ) +/*++ + +Routine Description: + + This routine translate a PCI slot number to a PCI device number. + This is a sandalfoot memory map implementation. + +Arguments: + + None. + +Return Value: + + Returns length of data written. + +--*/ + +{ + // + // Sandalfoot only has 1 PCI bus so bus number is unused + // + + UNREFERENCED_PARAMETER(BusNumber); + + return ((ULONG) ((PUCHAR) HalpPciConfigBase + HalpPciConfigSlot[SlotNumber])); + +} + + +ULONG +HalpPhase0SetPciDataByOffset ( + ULONG BusNumber, + ULONG SlotNumber, + PUCHAR Buffer, + ULONG Offset, + ULONG Length + ) + +/*++ + +Routine Description: + + This routine writes to PCI configuration space prior to bus handler installation. + +Arguments: + + None. + +Return Value: + + Returns length of data written. + +--*/ + +{ + PUCHAR to; + PUCHAR from; + ULONG tmpLength; + PULONG ulong_to, ulong_from; + + if (SlotNumber < HalpPciMaxSlots) { + + to = (PUCHAR)HalpPciConfigBase + HalpPciConfigSlot[SlotNumber]; + to += Offset; + from = Buffer; + + // The GXT150P graphics adapter requires the use of dword I/O + // to some of its PCI configuration registers. Therefore, this + // code uses dword I/O when possible. + + // If the bus address is not dword aligned or the length + // is not a multiple of 4 (dword size) bytes, then use byte I/O + if(((ULONG)to & 0x3)||(Length & 0x3)){ + tmpLength = Length; + while (tmpLength > 0) { + *to++ = *from++; + tmpLength--; + } + // If the bus address is dword aligned and the length is + // a multiple of 4 (dword size) bytes, then use dword I/O + }else{ + ulong_to = (PULONG) to; + ulong_from = (PULONG) from; + tmpLength = Length >> 2; + while (tmpLength > 0) { + *ulong_to++ = *ulong_from++; + tmpLength--; + } + } + + return(Length); + } + else { + return (0); + } +} + +ULONG +HalpPhase0GetPciDataByOffset ( + ULONG BusNumber, + ULONG SlotNumber, + PUCHAR Buffer, + ULONG Offset, + ULONG Length + ) + +/*++ + +Routine Description: + + This routine reads PCI config space prior to bus handlder installation. + +Arguments: + + None. + +Return Value: + + Amount of data read. + +--*/ + +{ + PUCHAR to; + PUCHAR from; + ULONG tmpLength; + PULONG ulong_to, ulong_from; + + if (SlotNumber < HalpPciMaxSlots) { + + from = (PUCHAR)HalpPciConfigBase + HalpPciConfigSlot[SlotNumber]; + from += Offset; + to = Buffer; + + // The GXT150P graphics adapter requires the use of dword I/O + // to some of its PCI configuration registers. Therefore, this + // code uses dword I/O when possible. + + // If the bus address is not dword aligned or the length + // is not a multiple of 4 (dword size) bytes, then use byte I/O + if(((ULONG)from & 0x3)||(Length & 0x3)){ + tmpLength = Length; + while (tmpLength > 0) { + *to++ = *from++; + tmpLength--; + } + // If the bus address is dword aligned and the length is + // a multiple of 4 (dword size) bytes, then use dword I/O + }else{ + ulong_to = (PULONG) to; + ulong_from = (PULONG) from; + tmpLength = Length >> 2; + while (tmpLength > 0) { + *ulong_to++ = *ulong_from++; + tmpLength--; + } + } + + return(Length); + } + else { + return (0); + } +} + diff --git a/private/ntos/nthals/haleagle/ppc/pxpcisup.h b/private/ntos/nthals/haleagle/ppc/pxpcisup.h new file mode 100644 index 000000000..a598de5e5 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxpcisup.h @@ -0,0 +1,54 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + pxpcisup.h + +Abstract: + + The module provides the PCI bus interfaces for PowerPC systems. + +Author: + + Jim Wooldridge (jimw@austin.vnet.ibm.com) + + +Revision History: + + + +--*/ + +extern ULONG HalpPciConfigSlot[]; +extern ULONG HalpPciMaxSlots; + +#define PCI_CONFIG_PHYSICAL_BASE 0x80800000 // physical base of PCI config space + +#define PCI_MEMORY_BASE 0xC0000000 + + + +typedef struct { + USHORT VendorID; + USHORT DeviceID; + USHORT Command; + USHORT Status; + UCHAR RevisionID; + UCHAR ClassCode[3]; + UCHAR CacheLineSize; + UCHAR LatencyTimer; + UCHAR HeaderType; + UCHAR BIST; + ULONG BaseAddress1; + ULONG BaseAddress2; + ULONG BaseAddress3; + ULONG BaseAddress4; + ULONG BaseAddress5; + ULONG BaseAddress6; + ULONG reserved1; + ULONG reserved2; + ULONG ROMbase; +} *PCI_CONFIG; + diff --git a/private/ntos/nthals/haleagle/ppc/pxport.c b/private/ntos/nthals/haleagle/ppc/pxport.c new file mode 100644 index 000000000..6c91f4b59 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxport.c @@ -0,0 +1,849 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +contains copyrighted material. Use of this file is restricted +by the provisions of a Motorola Software License Agreement. + +Module Name: + + pxport.c + +Abstract: + + This module implements the code that provides communication between + the kernel debugger on a PowerPC system. + + +Author: + + David N. Cutler (davec) 28-Apr-1991 + Chuck Bauman 02-Jun-1993 + +Environment: + + Kernel mode + +Revision History: + Steve Johns (sjohns@pets.sps.mot.com) + - added support for multple baud rates, alternate COM port + - implemented KdPortSave & KdPortRestore + +--*/ + +#include "halp.h" +#include "ppcserp.h" + +#include <pxmemctl.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; +ULONG KdCurrentBaudRate= 19200; +ULONG KdCurrentComPort = COM1_PORT; +ULONG HalpSavedBaudRate; +ULONG HalpSavedComPort; + +extern PVOID HalpIoControlBase; + +// +// Define serial port read and write addresses. +// + +#define SP_READ ((PSP_READ_REGISTERS)((PUCHAR)HalpIoControlBase + KdCurrentComPort)) +#define SP_WRITE ((PSP_WRITE_REGISTERS)((PUCHAR)HalpIoControlBase + KdCurrentComPort)) + + +// +// Define forward referenced prototypes. +// + +SP_LINE_STATUS +KdReadLsr ( + IN BOOLEAN WaitReason + ); + + +// +// Define baud rate divisor to be used on the debugger port. +// + +UCHAR HalpBaudRateDivisor = 6; + +// +// Define hardware PTE's that map the serial port used by the debugger. +// + + +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: + + DebugParameters - 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; + +/* + // + // Find the configuration information for the first serial port. + // + + if (LoaderBlock != NULL) { + MatchKey = 0; + ConfigurationEntry = KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot, + ControllerClass, + SerialController, + &MatchKey); + + } else { + ConfigurationEntry = NULL; + } + + if (DebugParameters->BaudRate != 0) { + BaudRate = DebugParameters->BaudRate; + } else { + BaudRate = 19200; + } + + + // + // If the serial configuration entry was not found or the frequency + // specified is not supported, then default the baud clock to 800000. + // + + BaudClock = 8000000; + if (ConfigurationEntry != NULL) { + List = (PCM_PARTIAL_RESOURCE_LIST)ConfigurationEntry->ConfigurationData; + Descriptor = &List->PartialDescriptors[List->Count]; + DeviceData = (PCM_SERIAL_DEVICE_DATA)Descriptor; + if ((DeviceData->BaudClock == 1843200) || + (DeviceData->BaudClock == 4233600) || + (DeviceData->BaudClock == 8000000)) { + BaudClock = DeviceData->BaudClock; + } + } + + HalpGetDivisorFromBaud( + BaudClock, + BaudRate, + &HalpBaudRateDivisor + ); + + +*/ + + // + // Map I/O space if it has not already been mapped. + // + + + if (HalpIoControlBase == NULL) { + + HalpIoControlBase = (PVOID)KePhase0MapIo(IO_CONTROL_PHYSICAL_BASE, + 0x20000); + + if ( !HalpIoControlBase ) { + return FALSE; + } + } + + + + // + // Set COM parameters + // + if (DebugParameters != NULL) { + if (DebugParameters->BaudRate == 0) + KdCurrentBaudRate = 19200; // default baud rate + else + KdCurrentBaudRate = DebugParameters->BaudRate; + + if (DebugParameters->CommunicationPort > 2) + return (FALSE); + KdCurrentComPort = COM1_PORT; // default COM port + if (DebugParameters->CommunicationPort == 1) + KdCurrentComPort = COM1_PORT; + if (DebugParameters->CommunicationPort == 2) + KdCurrentComPort = COM2_PORT; + + } + + HalpBaudRateDivisor = (UCHAR) ((1843200/16) / KdCurrentBaudRate); + + // + // If the debugger is not being enabled, then return. + // + + if (Initialize == FALSE) { + return TRUE; + } + + + + KdComPortInUse=(PUCHAR)KdCurrentComPort; + + + // + // 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 requested rate. + // + ((PSP_LINE_CONTROL)(&DataByte))->DivisorLatch = 1; + WRITE_REGISTER_UCHAR(&SP_WRITE->LineControl, DataByte); + WRITE_REGISTER_UCHAR(&SP_WRITE->TransmitBuffer, HalpBaudRateDivisor); + WRITE_REGISTER_UCHAR(&SP_WRITE->InterruptEnable, 0x0); + + // + // Clear the divisor latch and set the character size to eight bits + // with one stop bit and no parity checking. + // + + DataByte = 0; + ((PSP_LINE_CONTROL)(&DataByte))->CharacterSize = EIGHT_BITS; + 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. + // + + + Status = HalpGetByte(Input, FALSE); + 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; + PSP_MODEM_STATUS LsrByte; + + 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 = (PSP_MODEM_STATUS) 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. + +--*/ + +{ +DEBUG_PARAMETERS ComParams; + + if (HalpSavedComPort != KdCurrentComPort || + HalpSavedBaudRate != KdCurrentBaudRate) { + if (HalpSavedComPort == COM2_PORT) + ComParams.CommunicationPort = 2; + else + ComParams.CommunicationPort = 1; + ComParams.BaudRate = HalpSavedBaudRate; + KdPortInitialize(&ComParams, NULL, TRUE); + } +} + +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. + +--*/ + +{ + + HalpSavedBaudRate = KdCurrentBaudRate; + HalpSavedComPort = KdCurrentComPort; + 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 - Supplies 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/haleagle/ppc/pxpower.s b/private/ntos/nthals/haleagle/ppc/pxpower.s new file mode 100644 index 000000000..e02d56689 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxpower.s @@ -0,0 +1,67 @@ +//++ +// +// Copyright (c) 1993-1995 IBM Corporation +// +// Copyright (c) 1994, 1995 MOTOROLA, INC. All Rights Reserved. This file +// contains copyrighted material. Use of this file is restricted +// by the provisions of a Motorola Software License Agreement. +// +// Module Name: +// +// pxpower.s +// +// Abstract: +// +// This module implements the routines to flush cache on the PowerPC. +// +// Author: +// +// Steve Johns - Motorola +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// 12-Sep-94 saj Wrote it +// 25-Oct-94 saj Enable interrupts if 604 +// Set DOZE bit in HID0 before POW in MSR +// 25-Sep-95 kjr Added 603ev support. +//-- + +#include "kxppc.h" + + + .set HID0, 1008 // SPR # for HID0 + + + + LEAF_ENTRY(HalpProcessorIdle) + + mfmsr r.4 // Read MSR + ori r.4, r.4, 0x8000 // Enable External/Decrementer interrupts + + mfpvr r.0 // Read PVR + rlwinm r.0, r.0, 16, 15, 31 + cmpwi r.0, 3 // Is it a 603? + beq EnableDoze + cmpwi r.0, 6 // Is it a 603e? + beq EnableDoze + cmpwi r.0, 7 // Is it a 603ev? + beq EnableDoze + + b EnableInterrupts // If not, just enable interrupts + +EnableDoze: + mfspr r.3, HID0 // Set Doze mode in HID0 (bit 8) + oris r.3, r.3, 0x0080 + mtspr HID0, r.3 + sync + + oris r.4, r.4, 0x0004 // Set POW in MSR (bit 13) + +EnableInterrupts: + mtmsr r.4 + isync + + LEAF_EXIT(HalpProcessorIdle) diff --git a/private/ntos/nthals/haleagle/ppc/pxproc.c b/private/ntos/nthals/haleagle/ppc/pxproc.c new file mode 100644 index 000000000..5ec201f37 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxproc.c @@ -0,0 +1,212 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + pxproc.c + +Abstract: + + Stub functions for UP hals. + +Author: + + Ken Reneris (kenr) 22-Jan-1991 + +Environment: + + Kernel mode only. + +Revision History: + + Jim Wooldridge Ported to PowerPC + +--*/ + +#include "halp.h" + +UCHAR HalName[] = "PowerPC HAL"; + +BOOLEAN +HalpInitMP ( + IN ULONG Phase, + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ); + +extern VOID HalpInitializePciBus (VOID); +VOID HalpInitOtherBuses (VOID); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT,HalpInitMP) +#pragma alloc_text(INIT,HalStartNextProcessor) +#pragma alloc_text(INIT,HalAllProcessorsStarted) +#pragma alloc_text(INIT,HalReportResourceUsage) +#pragma alloc_text(INIT,HalReportResourceUsage) +#pragma alloc_text(INIT,HalpInitOtherBuses) +#endif + + + +BOOLEAN +HalpInitMP ( + IN ULONG Phase, + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ) +{ + return FALSE; + // do nothing +} + + +VOID +HalpResetAllProcessors ( + VOID + ) +{ +} + + +BOOLEAN +HalStartNextProcessor ( + IN PLOADER_PARAMETER_BLOCK LoaderBlock, + IN PKPROCESSOR_STATE ProcessorState + ) + +/*++ + +Routine Description: + + This function is called to start the next processor. + +Arguments: + + LoaderBlock - Supplies a pointer to the loader parameter block. + + ProcessorState - Supplies a pointer to the processor state to be + used to start the processor. + +Return Value: + + If a processor is successfully started, then a value of TRUE is + returned. Otherwise a value of FALSE is returned. If a value of + TRUE is returned, then the logical processor number is stored + in the processor control block specified by the loader block. + +--*/ + +{ + + PRESTART_BLOCK NextRestartBlock; + ULONG Number; + PKPRCB Prcb; + + // + // If there is more than one restart block then this is a multi- + // processor system. + // + // N.B. The first restart parameter block must be for the boot master + // and must represent logical processor 0. + // + // Scan the restart parameter blocks for a processor that is ready, + // but not running. If a processor is found, then fill in the restart + // processor state, set the logical processor number, and set start + // in the boot status. + // + + NextRestartBlock = SYSTEM_BLOCK->RestartBlock; + Number = 0; + while (NextRestartBlock != NULL) { + if ((NextRestartBlock->BootStatus.ProcessorReady != FALSE) && + (NextRestartBlock->BootStatus.ProcessorStart == FALSE)) { + RtlZeroMemory(&NextRestartBlock->u.Ppc, sizeof(PPC_RESTART_STATE)); + + // + // Set processor start address. + // + + NextRestartBlock->u.Ppc.Iar = ProcessorState->ContextFrame.Iar; + + // + // PowerPC linkage conventions pass parameters in registers + // r.3 thru r.10. Set all of them to allow as much flexibility + // to the kernel as possible. + // + + NextRestartBlock->u.Ppc.IntR3 = ProcessorState->ContextFrame.Gpr3; + NextRestartBlock->u.Ppc.IntR4 = ProcessorState->ContextFrame.Gpr4; + NextRestartBlock->u.Ppc.IntR5 = ProcessorState->ContextFrame.Gpr5; + NextRestartBlock->u.Ppc.IntR6 = ProcessorState->ContextFrame.Gpr6; + NextRestartBlock->u.Ppc.IntR7 = ProcessorState->ContextFrame.Gpr7; + NextRestartBlock->u.Ppc.IntR8 = ProcessorState->ContextFrame.Gpr8; + NextRestartBlock->u.Ppc.IntR9 = ProcessorState->ContextFrame.Gpr9; + NextRestartBlock->u.Ppc.IntR10 = ProcessorState->ContextFrame.Gpr10; + + Prcb = (PKPRCB)(LoaderBlock->Prcb); + Prcb->Number = (CCHAR)Number; + Prcb->RestartBlock = NextRestartBlock; + NextRestartBlock->BootStatus.ProcessorStart = 1; + return TRUE; + } + + Number++; + NextRestartBlock = NextRestartBlock->NextRestartBlock; + } + + return FALSE; +} + +BOOLEAN +HalAllProcessorsStarted ( + VOID + ) +{ + return TRUE; +} + +VOID +HalReportResourceUsage ( + VOID + ) +{ + INTERFACE_TYPE interfacetype; + ANSI_STRING AHalName; + UNICODE_STRING UHalName; + + interfacetype = Internal; + + RtlInitAnsiString (&AHalName, HalName); + RtlAnsiStringToUnicodeString (&UHalName, &AHalName, TRUE); + HalpReportResourceUsage ( + &UHalName, // descriptive name + interfacetype // device space interface type + ); + + interfacetype = Isa; + + HalpReportResourceUsage ( + &UHalName, // descriptive name + interfacetype // device space interface type + ); + + RtlFreeUnicodeString (&UHalName); + + // + // Registry is now intialized, see if there are any PCI buses + // + + HalpInitializePciBus (); + +#ifdef POWER_MANAGEMENT + HalInitSystemPhase2(); +#endif +} + + +VOID +HalpInitOtherBuses ( + VOID + ) +{ + // no other internal buses supported +} diff --git a/private/ntos/nthals/haleagle/ppc/pxprof.c b/private/ntos/nthals/haleagle/ppc/pxprof.c new file mode 100644 index 000000000..fdd31e5f1 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxprof.c @@ -0,0 +1,268 @@ + +/***************************************************************************** + +Copyright (c) 1993 Motorola Inc. + Copyright 1994 MOTOROLA, INC. All Rights Reserved. This file + contains copyrighted material. Use of this file is restricted + by the provisions of a Motorola Software License Agreement. + +Module Name: + + PXPROF.C + +Abstract: + + This implements the HAL profile functions: + + HalSetProfileInterval + HalStartProfileInterrupt + HalStopProfileInterrupt + HalCalibratePerformanceCounter + HalpProfileInterrupt + + +Author: + + Steve Johns 11-Feb-1994 + +Revision History: + Changed from using the DECREMENTER to 8254 Timer 1 10-Feb-94 + +******************************************************************************/ + +#include "halp.h" +#include "eisa.h" +#include "pxsiosup.h" + +#define TIMER ((PEISA_CONTROL)HalpIoControlBase) +#define TIMER0_COMMAND (COMMAND_8254_COUNTER0 + COMMAND_8254_RW_16BIT + COMMAND_8254_MODE2) + +ULONG HalpMaxProfileInterval = 540000; // 54 ms maximum +ULONG HalpMinProfileInterval = 10000; // 1 ms minimum +ULONG HalpProfileCount; +BOOLEAN HalpProfilingActive = FALSE; +ULONG HalpProfileInts = 0; + + +VOID HalStartProfileInterrupt ( + KPROFILE_SOURCE ProfileSource + ) + +/*++ + +Routine Description: + + This routine unmasks IRQ0 at the master interrupt controller, + enabling the profile interrupt. + + + N.B. This routine must be called at PROFILE_LEVEL while holding + the profile lock. + +Arguments: + + ProfileSource + +Return Value: + + None. + +--*/ + +{ + if (ProfileSource == ProfileTime) { + HalpProfilingActive = TRUE; + // + // Unmasks IRQ 0 (Timer 1) + // + HalEnableSystemInterrupt(PROFILE_VECTOR, PROFILE_LEVEL, Latched); + } + +} + + + + + + +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, rounded to the nearest 100ns units. + +--*/ + +{ + ULONG ActualInterval; + LARGE_INTEGER BigNumber; + + // + // Clamp the requested profile interval between the minimum and + // maximum supported values. + // + if (Interval < HalpMinProfileInterval) + Interval = HalpMinProfileInterval; + else + if (Interval > HalpMaxProfileInterval) + Interval = HalpMaxProfileInterval; + // + // Compute Timer 1 counts for requested interval. + // + BigNumber.QuadPart = Int32x32To64(Interval, TIMER_CLOCK_IN); + + BigNumber = RtlExtendedLargeIntegerDivide(BigNumber, 10000000, NULL); + HalpProfileCount = BigNumber.LowPart; + + // + // Program Timer 1 to Mode 2 & program the timer count register. + // + WRITE_REGISTER_UCHAR (&(TIMER->CommandMode1), TIMER0_COMMAND); + WRITE_REGISTER_UCHAR (&(TIMER->Timer1), (UCHAR)(HalpProfileCount & 0xff)); + WRITE_REGISTER_UCHAR (&(TIMER->Timer1), (UCHAR)(HalpProfileCount >> 8)); + // + // Compute actual interval. + // + BigNumber.QuadPart = Int32x32To64(HalpProfileCount, 10000000); + BigNumber = RtlExtendedLargeIntegerDivide(BigNumber,TIMER_CLOCK_IN, NULL); + ActualInterval = BigNumber.LowPart; + + return (ActualInterval); +} + + + + +BOOLEAN HalpHandleProfileInterrupt( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext, + IN PVOID TrapFrame + ) +{ + + if (HalpProfilingActive) + KeProfileInterrupt(TrapFrame); + + return (TRUE); +} + + + + +VOID +HalStopProfileInterrupt ( + KPROFILE_SOURCE ProfileSource + ) + +/*++ + +Routine Description: + + This routine masks IRQ 0 (Timer 1) at the interrupt controller, thereby + stopping profile interrupts. + + N.B. This routine must be called at PROFILE_LEVEL while holding the + profile lock. + +Arguments: + + ProfileSource + +Return Value: + + None. + +--*/ + +{ + + if (ProfileSource == ProfileTime) { + HalpProfilingActive = FALSE; + + // + // Program Timer 1 to Mode 2 & program the LSB of the timer. + // That should keep it from interrupting in case IRQ0 accidently + // gets enabled. + // + WRITE_REGISTER_UCHAR (&(TIMER->CommandMode1), TIMER0_COMMAND); + WRITE_REGISTER_UCHAR (&(TIMER->Timer1), (UCHAR)(HalpProfileCount & 0xff)); + + + // + // Mask IRQ 0 (Timer 1) + // + HalDisableSystemInterrupt(PROFILE_VECTOR, PROFILE_LEVEL); + } + +} + + + + + + +VOID +HalCalibratePerformanceCounter ( + IN volatile PLONG Number + ) + +/*++ + +Routine Description: + + This routine resets the performance counter value for the current + processor to zero. The reset is done such that the resulting value + is closely synchronized with other processors in the configuration. + +Arguments: + + Number - Supplies a pointer to count of the number of processors in + the configuration. + +Return Value: + + None. + +--*/ + +{ + + KSPIN_LOCK Lock; + KIRQL OldIrql; + + // + // Raise IRQL to HIGH_LEVEL, decrement the number of processors, and + // wait until the number is zero. + // + KeInitializeSpinLock(&Lock); + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + if (ExInterlockedDecrementLong(Number, &Lock) != RESULT_ZERO) { + do { + } while (*Number !=0); + } + + // + // Zero the Time Base registers + // + + HalpZeroPerformanceCounter(); + + // + // Restore IRQL to its previous value and return. + // + + KeLowerIrql(OldIrql); + return; +} diff --git a/private/ntos/nthals/haleagle/ppc/pxreset.s b/private/ntos/nthals/haleagle/ppc/pxreset.s new file mode 100644 index 000000000..ad4bfb697 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxreset.s @@ -0,0 +1,240 @@ +//++ +// +// Copyright (c) 1993 IBM Corporation +// +// Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +// contains copyrighted material. Use of this file is restricted +// by the provisions of a Motorola Software License Agreement. +// +// Module Name: +// +// pxreset.s +// +// Abstract: +// +// This module implements the routine HalpPowerPcReset, which can be +// used to return the PowerPC to Big Endian with cache flushed and +// branches to the rom based machine reset handler. +// +// Author: +// +// Steve Johns Sept-1994 +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// +// 3/21/95 saj Fixed HID0 getting trashed. +//-- + +#include "kxppc.h" + .new_section .text,"crx5" + + .extern HalpIoControlBase + .extern HalpSystemType + + .set ISA, r.1 + + .set HID0, 1008 + .set DISABLES, MASK_SPR(MSR_EE,1) | MASK_SPR(MSR_DR,1) | MASK_SPR(MSR_IR,1) + .set HID0_DCE, 0x4000 // 603 Data Cache Enable + .set HID0_ICE, 0x8000 // 603 Instruction Cache Enable + .set HID0_ICFI, 0x0800 // I-Cache Flash Invalidate + .set HID0_DCFI, 0x0400 // D-Cache Flash Invalidate + + + LEAF_ENTRY(HalpPowerPcReset) + + + lwz r.3,[toc]HalpSystemType(r.toc) // Get system type for later use. + lwz r.3, 0(r.3) + + LWI (r.4, 0xfff00100) // Address of ROM reset vector + mfspr r.5, HID0 + + LWI (r.7, 0x80000000) // I/O space for physical mode + + lwz ISA,[toc]HalpIoControlBase(r.toc) + lwz ISA,0(ISA) // Get base address of ISA I/O space + + + LWI (r.12, 0x800000A8) // Index to Eagle register 0xA8 + stw r.12, 0xCF8(ISA) + sync + lwz r.6, 0xCFC(ISA) + rlwinm r.6, r.6, 0, 0, 29 // Disable L2 cache + rlwinm r.6, r.6, 0, 21, 19 // Disable Machine Checks from Eagle + stw r.6, 0xCFC(ISA) // Disable the L2 cache + rlwinm r.6, r.6, 0, 27, 25 // Clear LE_MODE of Eagle register A8 + + mfmsr r.8 + rlwinm r.8, r.8, 0, ~MASK_SPR(MSR_EE,1) + isync + mtmsr r.8 // disable interrupts + cror 0,0,0 // N.B. 603e/ev Errata 15 + + bl here // get current address +here: + mflr r.9 // (r.9) = &here + addi r.9, r.9, BigEndian-here + rlwinm r.9, r.9, 0, 0x7fffffff // convert address to physical + + +// When we get here +// r.4 contains the address of the ROM resident Machine Reset +// handler. +// r.5 contains HID0 present value. +// r.6 contains Eagle register A8 value for switching to Big Endian +// r.7 contains the port address (real) used to switch memory +// endianness. +// r.8 contains MSR present value. +// r.9 contains the physical address of "BigEndian" + + + +// Disable D-Cache and Data address translation, flush I-Cache +// and disable interrupts. + + mr r.10, r.5 + ori r.5,r.5,HID0_DCE+HID0_ICE+HID0_ICFI+HID0_DCFI // Invalidate caches + rlwinm r.10, r.10, 0, ~HID0_DCE// turn off D-cache + rlwinm r.10, r.10, 0, ~HID0_ICE// turn off I-cache + sync + mtspr HID0, r.5 // Flash invalidate both caches + mtspr HID0, r.10 // Disable both caches + + rlwinm r.8, r.8, 0, ~MASK_SPR(MSR_DR,1) + isync + mtmsr r.8 // disable data address translation, + // disable interrupts. + cror 0,0,0 // N.B. 603e/ev Errata 15 + +// We will use a MTMSR instruction to switch to big-endian, untranslated, +// interrupts disabled at the same time. We use an RFI to effect the +// branch to the reset vector (0xFFF00100). + + li r.8, MASK_SPR(MSR_IP,1) + ori r.8, r.8, MASK_SPR(MSR_ME,1) + mtsrr1 r.8 // state = Machine Check Enabled + mtsrr0 r.9 // RFI to BigEndian + + + // + // Try to issue a hard reset. If this fails, the fall + // thru and continue to manually return to firmware. + // + + cmpwi r.3, 0 // Skip port 92 reset for BigBend. *BJ* + beq NoPort92 + + li r.9, 0xFF // All ones + stb r.9, 0x92(r.7) // Reset the System + eieio + lwz r.9, 0x21(r.7) // Flush the Eagle write buffers + sync + sync + sync + sync + + // + // Continue returning to firmware... + // + + +NoPort92: + + + stw r.12, 0xCF8(r.7) + sync + stw r.6, 0xCFC(r.7) // switch PCI bus to big-endian (Eagle) + li r.6, 0 + sync + rfi + + + .align 5 + +// +// When the assembler mode is Big-Endian, instructions are stored in the .OBJ +// in a different order. To be safe, we will place instructions in groups of +// fours, where the execution order within a group is not important. +BigEndian: + addi r.0, r.1, 0x138 // same both ways + addi r.0, r.1, 0x138 // same both ways + addi r.0, r.1, 0x138 // same both ways + addi r.0, r.1, 0x138 // same both ways + + addi r.0, r.1, 0x138 // same both ways + addi r.0, r.1, 0x138 // same both ways + addi r.0, r.1, 0x138 // same both ways + addi r.0, r.1, 0x138 // same both ways + + +// +// Return the processor as close as possible to the reset state +// + mtibatl 0, r.6 // Invalidate BAT registers + mtibatu 0, r.6 + mtibatl 1, r.6 + mtibatu 1, r.6 + mtibatl 2, r.6 + mtibatu 2, r.6 + mtibatl 3, r.6 + mtibatu 3, r.6 + + mtsr 0, r.6 // Zero the Segment Registers + mtsr 1, r.6 + mtsr 2, r.6 + mtsr 3, r.6 + mtsr 4, r.6 + mtsr 5, r.6 + mtsr 6, r.6 + mtsr 7, r.6 + mtsr 8, r.6 + mtsr 9, r.6 + mtsr 10, r.6 + mtsr 11, r.6 + mtsr 12, r.6 + mtsr 13, r.6 + mtsr 14, r.6 + mtsr 15, r.6 + + mtsprg 0,r.6 // Should get cleared in the firmware + mtsprg 1,r.6 // (used for branch table) + mtsprg 2,r.6 + mtsprg 3,r.6 + + li r.9,-1 // DECREMENTER = 0xFFFFFFFF + mtdec r.9 + li r.9, 128 // # TLBs on a 604 (603 has 32) + mtsrr0 r.4 // rfi target = 0xfff00100 + + li r.7, 0 + mtctr r.9 + nop + nop + +Invalidate_TLB: + tlbie r.7 // Invalidate Instruction & Data TLBs + nop + nop + nop + + addi r.7, r.7, 4096 // next TLB + nop + nop + nop + + bdnz Invalidate_TLB + nop + nop + nop + + rfi // go to machine reset handler + rfi + rfi + rfi + + LEAF_EXIT(HalpPowerPcReset) diff --git a/private/ntos/nthals/haleagle/ppc/pxreturn.c b/private/ntos/nthals/haleagle/ppc/pxreturn.c new file mode 100644 index 000000000..2638d8e6a --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxreturn.c @@ -0,0 +1,133 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +contains copyrighted material. Use of this file is restricted +by the provisions of a Motorola Software License Agreement. + +Module Name: + + pxreturn.c + +Abstract: + + This module implements the HAL return to firmware function. + + +Author: + + David N. Cutler (davec) 21-Aug-1991 + +Revision History: + + Jim Wooldridge (jimw@austin.vnet.ibm.com) Initial Power PC port + + Keyboard mapping code was ported to PPC. + This function is currently a stub since our firmware is big endian + +--*/ +#include "halp.h" +#include "pxsystyp.h" + + +// +// Define keyboard registers structure. +// + +typedef struct _KBD_REGISTERS { + union { + UCHAR Output; + UCHAR Input; + } Data; + + union { + UCHAR Status; + UCHAR Command; + } Control; +} KBD_REGISTERS; + +#define KBD_IBF_MASK 2 // input buffer full mask + +#define KBD_DATA_PORT 0x60 +#define KBD_COMMAND_PORT 0x64 +#define KbdGetStatus() (READ_REGISTER_UCHAR(&HalpIoControlBase + KBD_COMMAND_PORT)) +#define KbdStoreCommand(Byte) WRITE_REGISTER_UCHAR(&HalpIoControlBase + KBD_COMMAND_PORT, Byte) +#define KbdStoreData(Byte) WRITE_REGISTER_UCHAR(&HalpIoControlBase + KBD_DATA_PORT, Byte) +#define KbdGetData() (READ_REGISTER_UCHAR(&HalpIoControlBase + KBD_DATA_PORT)) + +VOID +HalpPowerPcReset( + VOID + ); + +VOID HalpFlushAndDisableL2(VOID); + + + +VOID +HalReturnToFirmware( + IN FIRMWARE_REENTRY Routine + ) + +/*++ + +Routine Description: + + This function returns control to the specified firmware routine. + In most cases it generates a soft reset 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 HalPowerDownRoutine: + case HalRestartRoutine: + case HalRebootRoutine: + case HalInteractiveModeRoutine: + HalpDisableInterrupts(); + if (HalpSystemType == MOTOROLA_BIG_BEND) + HalpFlushAndDisableL2(); + HalpPowerPcReset(); // does not return + + case HalHaltRoutine: + + // + // Hang looping. + // + + for (;;) { + } + + default: + KdPrint(("HalReturnToFirmware invalid argument\n")); + KeLowerIrql(OldIrql); + DbgBreakPoint(); + } +} + diff --git a/private/ntos/nthals/haleagle/ppc/pxs3.h b/private/ntos/nthals/haleagle/ppc/pxs3.h new file mode 100644 index 000000000..96f669688 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxs3.h @@ -0,0 +1,760 @@ +/*++ + +Copyright (c) 1992 ACER Labs Inc. + +Module Name: + + pxs3.h + +Abstract: + + This header file defines the S3 86C911 GUI accelerator registers. + +Author: + + Version 1.0 Kevin Chen 2-Apr-1992 + Version 2.0 Andrew Chou Nov-24-1992 + Version 3.0 Jess Botts Oct-06-1993 Power PC Initial Version + +--*/ + +#define VERTICALRESOLUTION 768 +#define HORIZONTALRESOLUTION 1024 +#define OriginalPoint 0 +#define BLUE 192 +#define WHITE 255 +#define CRT_OFFSET 2 +#define SEQ_OFFSET 27 +#define GRAPH_OFFSET 32 +#define ATTR_OFFSET 41 + +UCHAR DAC_Table[64] = { + // DAC for mode 3 + 0,16, 4,20, 1,17, 5,21, + 32,48,36,52,33,49,37,53, + 8,24,12,28, 9,25,13,29, + 40,56,44,60,41,57,45,61, + 2,18, 6,22, 3,19, 7,23, + 34,50,38,54,35,51,39,55, + 10,26,14,30,11,27,15,31, + 42,58,46,62,43,59,47,63 + }; + +UCHAR DAC_Color[4] = {0x00, 0x2a, 0x15, 0x3f}; + +// +// Define virtual address of the video memory and control registers. +// + +extern PVOID HalpIoControlBase; + +// +// Define S3 register I/O Macros +// + +//============================================================================= +// +// IBMBJB Changed the semicolons separating statements in the write macros to +// commas so that if the macro is used as the only statement in a loop +// all of the statements in the macro will be part of the loop. +// +// Commas were used instead of putting braces around the statements +// because if the macro is used in the true part of a conditional the +// braces will cause the compiler to generate a syntax error. + +#define WRITE_S3_UCHAR(port,data) \ + *(volatile unsigned char *)((ULONG)HalpIoControlBase + (port)) = (UCHAR)(data), \ + KeFlushWriteBuffer() + +#define WRITE_S3_USHORT(port,data) \ + *(volatile PUSHORT)((ULONG)HalpIoControlBase + (port)) = (USHORT)(data), \ + KeFlushWriteBuffer() + +#define READ_S3_UCHAR(port) \ + *(volatile unsigned char *)((ULONG)HalpIoControlBase + (port)) + +#define READ_S3_USHORT(port) \ + *(volatile unsigned short *)((ULONG)HalpIoControlBase + (port)) + +#define READ_S3_VRAM(port) \ + *(HalpVideoMemoryBase + (port)) + +#define WRITE_S3_VRAM(port,data) \ + *(HalpVideoMemoryBase + (port)) = (data), \ + KeFlushWriteBuffer() + +//============================================================================= + +#define DISPLAY_BITS_PER_PIXEL 8 // display bits per pixel +#define NUMBER_OF_COLORS 256 // number of colors + +#define CURSOR_WIDTH 64 // width of hardware cursor +#define CURSOR_HEIGHT 64 // height of hardware cursor +#define CURSOR_BITS_PER_PIXEL 2 // hardware cursor bits per pixel + +// +// S3 86C911 GUI, accelerator Video Controller Definitions. +// +// Define video register format. +// +#define PosID_LO 0x100 // R/W +#define PosID_HI 0x101 // R/W +#define Setup_OP 0x102 // R/W +#define Chck_Ind 0x105 // R +#define Mono_3B4 0x3B4 // R/W +#define Mono_3B5 0x3B5 // R/W +#define MDA_Mode 0x3B8 // W +#define HGC_SLPEN 0x3B9 // R/W +#define Stat1_MonoIn 0x3BA // R +#define FC_MonoW 0x3BA // W +#define HGC_CLPEN 0x3BB // W +#define HGC_Config 0x3BF // W +#define Attr_Index 0x3C0 // R/W +#define Attr_Data 0x3C0 // R/W +#define Stat0_In 0x3C2 // R +#define MiscOutW 0x3C2 // W +#define VSub_EnB 0x3C3 // R/W +#define Seq_Index 0x3C4 // R/W +#define Seq_Data 0x3C5 // R/W +#define DAC_Mask 0x3C6 // R/W +#define DAC_RIndex 0x3C7 // W +#define DAC_Status 0x3C7 // W +#define DAC_WIndex 0x3C8 // R/W +#define DAC_Data 0x3C9 // R/W +#define FC_Read 0x3CA // R +#define MiscOutR 0x3CC // R +#define GC_Index 0x3CE // R/W +#define GC_Data 0x3CF // R/W +#define S3_3D4_Index 0x3D4 // R/W +#define S3_3D5_Data 0x3D5 // R/W + +#define CGA_Mode 0x3D8 // W +#define CGA_Color 0x3D9 // W +#define Stat1_In 0x3DA // R +#define FC_Write 0x3DA // W +#define CLPEN 0x3DB +#define SLPEN 0x3DC + +// +// Define Enhanced registers for S3_86C911 +// + +#define SUBSYS_STAT 0x42E8 // R +#define SUBSYS_CNTL 0x42E8 // W +#define SUBSYS_ENB 0x46E8 // R/W +#define ADVFUNC_CNTL 0x4AE8 // W +#define CUR_Y 0x82E8 // R/W +#define CUR_X 0x86E8 // R/W +#define DESTY 0x8AE8 // W +#define AXIAL_STEP 0x8AE8 // W +#define DESTX 0x8EE8 // W +#define DIAG_STEP 0x8EE8 // W +#define ERR_TERM 0x92E8 // R +#define MAJ_AXIS_PCNT 0x96E8 // W +#define RWIDTH 0x96E8 // W +#define GP_STAT 0x9AE8 // R +#define DRAW_CMD 0x9AE8 // W +#define SHORT_STROKE 0x9EE8 // W +#define BKGD_COLOR 0xA2E8 // W +#define FRGD_COLOR 0xA6E8 // W +#define WRITE_MASK 0xAAE8 // W +#define READ_MASK 0xAEE8 // W +#define BKGD_MIX 0xB6E8 // W +#define FRGD_MIX 0xBAE8 // W +#define MULTIFUNC_CNTL 0xBEE8 // W +#define RHEIGHT 0xBEE8 // W +#define PIX_TRANS 0xE2E8 // W + + +// +// Define Attribute Controller Indexes : ( out 3C0, Index ) +// + +#define PALETTE0 0 +#define PALETTE1 1 +#define PALETTE2 2 +#define PALETTE3 3 +#define PALETTE4 4 +#define PALETTE5 5 +#define PALETTE6 6 +#define PALETTE7 7 +#define PALETTE8 8 +#define PALETTE9 9 +#define PALETTE10 10 +#define PALETTE11 11 +#define PALETTE12 12 +#define PALETTE13 13 +#define PALETTE14 14 +#define PALETTE15 15 +#define ATTR_MODE_CTRL 16 +#define BORDER_COLOR 17 +#define COLOR_PLANE_ENABLE 18 +#define HORI_PIXEL_PANNING 19 +#define PIXEL_PADDING 20 + +// +// Define Sequencer Indexes ( out 3C4, Index) +// + +#define RESET 0 +#define CLOCKING_MODE 1 +#define ENABLE_WRITE_PLANE 2 +#define CHARACTER_FONT_SELECT 3 +#define MEMORY_MODE_CONTROL 4 + +// +// Define Graphics Controller Index ( out 3CE, Index ) +// + +#define SET_RESET 0 +#define ENABLE_SET_RESET 1 +#define COLOR_COMPARE 2 +#define DATA_ROTATE 3 +#define READ_PLANE_SELECT 4 +#define GRAPHICS_CTRL_MODE 5 +#define MEMORY_MAP_MODE 6 +#define COLOR_DONT_CARE 7 +#define BIT_MASK 8 + +// +// Define CRTC, VGA S3, SYS_CTRL Index : ( Out 3D4, Index ) +// +// Define CRTC Controller Indexes +// + +#define HORIZONTAL_TOTAL 0 +#define HORIZONTAL_DISPLAY_END 1 +#define START_HORIZONTAL_BLANK 2 +#define END_HORIZONTAL_BLANK 3 +#define HORIZONTAL_SYNC_POS 4 +#define END_HORIZONTAL_SYNC 5 +#define VERTICAL_TOTAL 6 +#define CRTC_OVERFLOW 7 +#define PRESET_ROW_SCAN 8 +#define MAX_SCAN_LINE 9 +#define CURSOR_START 10 +#define CURSOR_END 11 +#define START_ADDRESS_HIGH 12 +#define START_ADDRESS_LOW 13 +#define CURSOR_LOCATION_HIGH 14 +#define CURSOR_FCOLOR 14 +#define CURSOR_BCOLOR 15 +#define CURSOR_LOCATION_LOW 15 +#define VERTICAL_RETRACE_START 16 +#define VERTICAL_RETRACE_END 17 +#define VERTICAL_DISPLAY_END 18 +#define OFFSET_SCREEN_WIDTH 19 +#define UNDERLINE_LOCATION 20 +#define START_VERTICAL_BLANK 21 +#define END_VERTICAL_BLANK 22 +#define CRT_MODE_CONTROL 23 +#define LINE_COMPARE 24 +#define CPU_LATCH_DATA 34 +#define ATTRIBUTE_INDEX1 36 +#define ATTRIBUTE_INDEX2 38 + +// +// Define VGA S3 Indexes +// +#define S3R0 0x30 +#define S3R1 0x31 +#define S3R2 0x32 +#define S3R3 0x33 +#define S3R4 0x34 +#define S3R5 0x35 +#define S3R6 0x36 +#define S3R7 0x37 +#define S3R8 0x38 +#define S3R9 0x39 +#define S3R0A 0x3A +#define S3R0B 0x3B +#define S3R0C 0x3C +#define SC0 0x40 +#define SC2 0x42 +#define SC3 0x43 +#define SC5 0x45 + +// +// Define System Control Indexes +// +#define SYS_CNFG 64 +#define SOFT_STATUS 65 +#define MODE_CTRL 66 +#define EXT_MODE 67 +#define HGC_MODE 69 +#define HGC_ORGX0 70 +#define HGC_ORGX1 71 +#define HGC_ORGY0 72 +#define HGC_ORGY1 73 +#define HGC_YSTART0 76 +#define HGC_YSTART1 77 +#define HGC_DISPX 78 +#define HGC_DISPY 79 + +#define ENABLE_HARDWARE_CURSOR 1 +#define DISABLE_HARDWARE_CURSOR 0 + +// +// define advanced function control register structure +// +#define RES_640x480 0 +#define RES_1024x768 1 +#define RES_800x600 1 + +#define ENABLE_VGA 6 +#define ENABLE_ENHANCED 7 + +// +// define draw command register values +// +#define NOP_COMMAND 0x0 +#define DRAW_LINE_COMMAND 0x2000 +#define RECTANGLE_FILL_COMMAND 0x4000 +#define BITBLT_COMMAND 0xc000 +#define BYTE_SWAP 0x1000 +#define NO_BYTE_SWAP 0x0 +#define SIXTEEN_BIT_BUS 0x0200 +#define EIGHT_BIT_BUS 0x0 +#define WAIT 0x0100 +#define NO_WAIT 0x0 +#define R0 0x0 +#define R45 0x20 +#define R90 0x40 +#define R135 0x60 +#define R180 0x80 +#define R225 0xa0 +#define R270 0xc0 +#define R315 0xe0 +#define XMAJ 0x0 +#define YMAJ 0x40 +#define XPositive 0x20 +#define YPositive 0x80 +#define XNegative 0x0 +#define YNegative 0x0 + +#define DRAW_YES 0x10 +#define DRAW_NO 0x0 +#define RADIAL 8 +#define XY_BASE 0 +#define LAST_PIXEL_OFF 4 +#define LAST_PIXEL_ON 0 +#define MULTIPLE_PIXEL 2 +#define SINGLE_PIXEL 0 +#define DRAW_READ 0 +#define DRAW_WRITE 1 + +#define SSV_DRAW 0x1000 +#define SSV_MOVE 0x0 + +#define OneEmpty 0x80 +#define TwoEmpty 0x40 +#define ThreeEmpty 0x20 +#define FourEmpty 0x10 +#define FiveEmpty 0x8 +#define SixEmpty 0x4 +#define SevenEmpty 0x2 +#define EightEmpty 0x1 + +#define BACKGROUND_COLOR 0 +#define FOREGROUND_COLOR 0x20 +#define CPU_DATA 0x40 +#define DISPLAY_MEMORTY 0x60 +#define NOT_SCREEN 0 +#define LOGICAL_ZERO 1 +#define LOGICAL_ONE 2 +#define LEAVE_ALONE 3 +#define NOT_NEW 4 +#define SCREEN_XOR_NEW 5 +#define NOT_SCREEN_XOR_NEW 6 +#define OVERPAINT 7 //( NEW ) +#define NOT_SCREEN_OR_NOT_NEW 8 +#define SCREEN_OR_NOT_NEW 9 +#define NOT_SCREEN_OR_NEW 10 +#define SCREEN_OR_NEW 11 +#define SCREEN_AND_NEW 12 +#define NOT_SCREEN_AND_NEW 13 +#define SCREEN_AND_NOT_NEW 14 +#define NOT_SCREEN_AND_NOT_NEW 15 + +#define BEE8_1H 1 +#define BEE8_2H 2 +#define BEE8_3H 3 +#define BEE8_4H 4 +#define BEE8_0H 0 +#define L_CLIP 0x1000 +#define R_CLIP 0x2000 +#define B_CLIP 0x3000 +#define T_CLIP 0x4000 + +#define DATA_EXTENSION 0xa000 // 10100000B +#define CPU_EXT 0x80 +#define DISPLAY_EXT 0xc0 +#define NO_EXTENSION 0x0 +#define PACK_DATA 0x4 +#define NO_PACK_DATA 0x0 +#define SET_THIS_BIT_TO_ZERO 0; + +// +// Define bits per pixel codes. +// +#define ONE_BIT_PER_PIXEL 0 // 1-bit per pixel +#define TWO_BITS_PER_PIXEL 1 // 2-bits per pixel +#define FOUR_BITS_PER_PIXEL 2 // 4-bits per pixel +#define EIGHT_BITS_PER_PIXEL 3 // 8-bits per pixel + +// +// Define address step value. +// +#define ADDRESS_STEP_INCREMENT 1 // vram transfer address increment + +// +// Define cross hair thickness values. +// +#define ONE_PIXEL_THICK 0x0 // one pixel in thickness +#define THREE_PIXELS_THICK 0x1 // three pixels in thickness +#define FIVE_PIXELS_THICK 0x2 // five pixels in thickness +#define SEVEN_PIXELS_THICK 0x3 // seven pixels in thickness + +// +// Define multiplexer control values. +// +#define ONE_TO_ONE 0x0 // 1:1 multiplexing +#define FOUR_TO_ONE 0x1 // 4:1 multiplexing +#define FIVE_TO_ONE 0x2 // 5:1 multiplexing + +// +// Define cursor origin values. +// + +#define CURSOR_X_ORIGIN (((2*HORIZONAL_SYNC_VALUE)+BACK_PORCH_VALUE)*4-36) +#define CURSOR_Y_ORIGIN ((VERTICAL_BLANK_VALUE/2)+24) + +ULONG HotspotX, HotspotY; + +// Extended VGA BIOS +#define SUPER_VGA_SUPPORT 4FH +#define RET_EXT_VGA_INFO 00H +#define RET_EXT_VGA_MODE_INFO 01H +#define SET_EXT_VGA_MODE 02H +#define QUERY_CUR_EXT_VGA_MODE 03H + +#define SAVE_RESTORE_FUNCTION 04H +// Function 04.0 Query Save/Restore Buffer Size +#define GET_SAVE_BUFFER_SIZE 00H +// Function 04.1 Save Extended Video state +#define SAVE_STATE 01H +// Function 04.2 Restore Extended VGA state +#define RESTORE_STATE 02H + +#define WINDOWS_CONTROL 05H +// Function 05.0 Set Window Control +#define SELECT_PAGE_TO_BE_MAPPED 00H +// fUNCTION 05.1 Get Window Control Setting +#define GET_PAGE_MAPPED 01H + +#define SET_RESET_DUAL_DISPLAY_MODE FFH + +BOOLEAN ColorMonitor; +PVOID S3_3x4, S3_3x5; +UCHAR VideoParam[62] = { +// Mode +3 480 Lines +// External Registers 3C3, 3C2 +0x01,0x67, + +//============================================================================= +// +// IBMBJB changed value at offset 17 (5th number on second line) from 0x8e +// to 0xae to disable the vertical retrace interrupt + +// CRT Controller Registers 3D4, 3D5 +0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,0x00,0x4f,0x0d,0x0e,0x00, +// 0x00,0x00,0x00,0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,0xff, + 0x00,0x00,0x00,0x9c,0xae,0x8f,0x28,0x1f,0x96,0xb9,0xa3,0xff, + +//============================================================================= + +// Sequencer Registers 3C4, 3C5 +// 0x01,0x01,0x03,0x00,0x02, +0x01,0x20,0x03,0x00,0x02, + +// Graphic Control Registers +0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,0xff, + +// Attribute Controller Registers +0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,0x38,0x39,0x3a, +0x3b,0x3c,0x3d,0x3e,0x3f,0x0c,0x00,0x0f,0x08,0x00}; + + +UCHAR VGAFont8x16[4096] = { +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 00 +0x00,0x00,0x7E,0x81,0xA5,0x81,0x81,0xBD,0x99,0x81,0x81,0x7E,0x00,0x00,0x00,0x00, // 1 +0x00,0x00,0x7E,0xFF,0xFF,0xDB,0xFF,0xFF,0xC3,0xE7,0xFF,0x7E,0x00,0x00,0x00,0x00, // 2 +0x00,0x00,0x00,0x00,0x6C,0xFE,0xFE,0xFE,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00, // 3 +0x00,0x00,0x00,0x00,0x10,0x38,0x7C,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00,0x00, // 4 +0x00,0x00,0x00,0x18,0x3C,0x3C,0xE7,0xE7,0xE7,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, // 5 +0x00,0x00,0x00,0x18,0x3C,0x7E,0xFF,0xFF,0x7E,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, // 6 +0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,0x00, // 7 +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE7,0xC3,0xC3,0xE7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, // 8 +0x00,0x00,0x00,0x00,0x00,0x3C,0x66,0x42,0x42,0x66,0x3C,0x00,0x00,0x00,0x00,0x00, // 9 +0xFF,0xFF,0xFF,0xFF,0xFF,0xC3,0x99,0xBD,0xBD,0x99,0xC3,0xFF,0xFF,0xFF,0xFF,0xFF, // a +0x00,0x00,0x3E,0x0E,0x1A,0x32,0x78,0xCC,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00, // b +0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x3C,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00, // c +0x00,0x00,0x30,0x38,0x3C,0x36,0x33,0x30,0x30,0x70,0xF0,0xE0,0x00,0x00,0x00,0x00, // d +0x00,0x00,0x7F,0x63,0x7F,0x63,0x63,0x63,0x63,0x67,0xE7,0xE6,0xC0,0x00,0x00,0x00, // e +0x00,0x00,0x00,0x18,0x18,0xDB,0x3C,0xE7,0x3C,0xDB,0x18,0x18,0x00,0x00,0x00,0x00, // f + +0x00,0x80,0xC0,0xE0,0xF0,0xF8,0xFE,0xF8,0xF0,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00, // 10 +0x00,0x02,0x06,0x0E,0x1E,0x3E,0xFE,0x3E,0x1E,0x0E,0x06,0x02,0x00,0x00,0x00,0x00, // 1 +0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00,0x00, // 2 +0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x66,0x00,0x00,0x00,0x00, // 3 +0x00,0x00,0x7F,0xDB,0xDB,0xDB,0x7B,0x1B,0x1B,0x1B,0x1B,0x1B,0x00,0x00,0x00,0x00, // 4 +0x00,0x7C,0xC6,0x60,0x38,0x6C,0xC6,0xC6,0x6C,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00, // 5 +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFE,0xFE,0xFE,0x00,0x00,0x00,0x00, // 6 +0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x7E,0x3C,0x18,0x7E,0x00,0x00,0x00,0x00, // 7 +0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00, // 8 +0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00, // 9 +0x00,0x00,0x00,0x00,0x00,0x18,0x0C,0xFE,0x0C,0x18,0x00,0x00,0x00,0x00,0x00,0x00, // a +0x00,0x00,0x00,0x00,0x00,0x30,0x60,0xFE,0x60,0x30,0x00,0x00,0x00,0x00,0x00,0x00, // b +0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xC0,0xC0,0xFE,0x00,0x00,0x00,0x00,0x00,0x00, // c +0x00,0x00,0x00,0x00,0x00,0x28,0x6C,0xFE,0x6C,0x28,0x00,0x00,0x00,0x00,0x00,0x00, // d +0x00,0x00,0x00,0x00,0x10,0x38,0x38,0x7C,0x7C,0xFE,0xFE,0x00,0x00,0x00,0x00,0x00, // e +0x00,0x00,0x00,0x00,0xFE,0xFE,0x7C,0x7C,0x38,0x38,0x10,0x00,0x00,0x00,0x00,0x00, // f + +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 20 +0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00, // 1 +0x00,0x66,0x66,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 2 +0x00,0x00,0x6C,0x6C,0xFE,0x6C,0x6C,0x6C,0x6C,0xFE,0x6C,0x6C,0x00,0x00,0x00,0x00, // 3 +0x00,0x18,0x18,0x7C,0xC6,0xC2,0x7C,0x86,0xC6,0x7C,0x18,0x18,0x00,0x00,0x00,0x00, // 4 +0x00,0x00,0x00,0x00,0xC2,0xC6,0x0C,0x18,0x30,0x60,0xC6,0x86,0x00,0x00,0x00,0x00, // 5 +0x00,0x00,0x38,0x6C,0x6C,0x38,0x76,0xDC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, // 6 +0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 7 +0x00,0x00,0x0C,0x18,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x0C,0x00,0x00,0x00,0x00, // 8 +0x00,0x00,0x30,0x18,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x18,0x30,0x00,0x00,0x00,0x00, // 9 +0x00,0x00,0x00,0x00,0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00, // a +0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00, // b +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30,0x60,0x00,0x00, // c +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // d +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00, // e +0x00,0x00,0x00,0x00,0x02,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x00,0x00,0x00,0x00, // f + +0x00,0x00,0x38,0x6C,0xC6,0xC6,0xD6,0xD6,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00, // 30 +0x00,0x00,0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00, // 1 +0x00,0x00,0x7C,0xC6,0x06,0x0C,0x18,0x30,0x60,0xC0,0xC6,0xFE,0x00,0x00,0x00,0x00, // 2 +0x00,0x00,0x7C,0xC6,0x06,0x06,0x3C,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00, // 3 +0x00,0x00,0x0C,0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00, // 4 +0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xFC,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00, // 5 +0x00,0x00,0x38,0x60,0xC0,0xC0,0xFC,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, // 6 +0x00,0x00,0xFE,0xC6,0x06,0x06,0x0C,0x18,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00, // 7 +0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7C,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, // 8 +0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7E,0x06,0x06,0x06,0x0C,0x78,0x00,0x00,0x00,0x00, // 9 +0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00, // a +0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x30,0x60,0x00,0x00, // b +0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00, // c +0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // d +0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00, // e +0x00,0x00,0x7C,0xC6,0xC6,0x0C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00, // f + +0x00,0x00,0x00,0x7C,0xC6,0xC6,0xDE,0xDE,0xDE,0xDC,0xC0,0x7C,0x00,0x00,0x00,0x00, // 40 +0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, // 1 +0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x66,0x66,0x66,0x66,0xFC,0x00,0x00,0x00,0x00, // 2 +0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x00,0x00,0x00,0x00, // 3 +0x00,0x00,0xF8,0x6C,0x66,0x66,0x66,0x66,0x66,0x66,0x6C,0xF8,0x00,0x00,0x00,0x00, // 4 +0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00, // 5 +0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00, // 6 +0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xDE,0xC6,0xC6,0x66,0x3A,0x00,0x00,0x00,0x00, // 7 +0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, // 8 +0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, // 9 +0x00,0x00,0x1E,0x0C,0x0C,0x0C,0x0C,0x0C,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00, // a +0x00,0x00,0xE6,0x66,0x66,0x6C,0x78,0x78,0x6C,0x66,0x66,0xE6,0x00,0x00,0x00,0x00, // b +0x00,0x00,0xF0,0x60,0x60,0x60,0x60,0x60,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00, // c +0x00,0x00,0xC6,0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, // d +0x00,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, // e +0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, // f + +0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00, // 50 +0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xD6,0xDE,0x7C,0x0C,0x0E,0x00,0x00, // 1 +0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x6C,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00, // 2 +0x00,0x00,0x7C,0xC6,0xC6,0x60,0x38,0x0C,0x06,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, // 3 +0x00,0x00,0x7E,0x7E,0x5A,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, // 4 +0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, // 5 +0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x10,0x00,0x00,0x00,0x00, // 6 +0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0xEE,0x6C,0x00,0x00,0x00,0x00, // 7 +0x00,0x00,0xC6,0xC6,0x6C,0x7C,0x38,0x38,0x7C,0x6C,0xC6,0xC6,0x00,0x00,0x00,0x00, // 8 +0x00,0x00,0x66,0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, // 9 +0x00,0x00,0xFE,0xC6,0x86,0x0C,0x18,0x30,0x60,0xC2,0xC6,0xFE,0x00,0x00,0x00,0x00, // a +0x00,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00, // b +0x00,0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x06,0x02,0x00,0x00,0x00,0x00, // c +0x00,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00, // d +0x10,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // e +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00, // f + +0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 60 +0x00,0x00,0x00,0x00,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, // 1 +0x00,0x00,0xE0,0x60,0x60,0x78,0x6C,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x00,0x00, // 2 +0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC0,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, // 3 +0x00,0x00,0x1C,0x0C,0x0C,0x3C,0x6C,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, // 4 +0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, // 5 +0x00,0x00,0x38,0x6C,0x64,0x60,0xF0,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00, // 6 +0x00,0x00,0x00,0x00,0x00,0x3E,0x66,0x66,0x66,0x66,0x66,0x3E,0x06,0x66,0x3C,0x00, // 7 +0x00,0x00,0xE0,0x60,0x60,0x6C,0x76,0x66,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00, // 8 +0x00,0x00,0x18,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, // 9 +0x00,0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00, // a +0x00,0x00,0xE0,0x60,0x60,0x66,0x6C,0x78,0x78,0x6C,0x66,0xE6,0x00,0x00,0x00,0x00, // b +0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, // c +0x00,0x00,0x00,0x00,0x00,0x6C,0xFE,0xD6,0xD6,0xD6,0xC6,0xC6,0x00,0x00,0x00,0x00, // d +0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00, // e +0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, // f + +0x00,0x00,0x00,0x00,0x00,0xFC,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0x60,0xF0,0x00, // 70 +0x00,0x00,0x00,0x00,0x00,0x7E,0xCC,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0x0C,0x1E,0x00, // 1 +0x00,0x00,0x00,0x00,0x00,0xDC,0x76,0x66,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00, // 2 +0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0x60,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00,0x00, // 3 +0x00,0x00,0x10,0x30,0x30,0xFC,0x30,0x30,0x30,0x30,0x36,0x1C,0x00,0x00,0x00,0x00, // 4 +0x00,0x00,0x00,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, // 5 +0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00,0x00,0x00,0x00, // 6 +0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0x6C,0x00,0x00,0x00,0x00, // 7 +0x00,0x00,0x00,0x00,0x00,0xC6,0x6C,0x38,0x38,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00, // 8 +0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0xF8,0x00, // 9 +0x00,0x00,0x00,0x00,0x00,0xFE,0xCC,0x18,0x30,0x60,0xC6,0xFE,0x00,0x00,0x00,0x00, // a +0x00,0x00,0x0E,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00, // b +0x00,0x00,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00, // c +0x00,0x00,0x70,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00, // d +0x00,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // e +0x00,0x00,0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xC6,0xFE,0x00,0x00,0x00,0x00,0x00, // f + +0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x0C,0x06,0x7C,0x00,0x00, // 80 +0x00,0x00,0xCC,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, // 1 +0x00,0x0C,0x18,0x30,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, // 2 +0x00,0x10,0x38,0x6C,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, // 3 +0x00,0x00,0xCC,0x00,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, // 4 +0x00,0x60,0x30,0x18,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, // 5 +0x00,0x38,0x6C,0x38,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, // 6 +0x00,0x00,0x00,0x00,0x3C,0x66,0x60,0x60,0x66,0x3C,0x0C,0x06,0x3C,0x00,0x00,0x00, // 7 +0x00,0x10,0x38,0x6C,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, // 8 +0x00,0x00,0xC6,0x00,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, // 9 +0x00,0x60,0x30,0x18,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, // a +0x00,0x00,0x66,0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, // b +0x00,0x18,0x3C,0x66,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, // c +0x00,0x60,0x30,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, // d +0x00,0xC6,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, // e +0x38,0x6C,0x38,0x00,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, // f + +0x18,0x30,0x60,0x00,0xFE,0x66,0x60,0x7C,0x60,0x60,0x66,0xFE,0x00,0x00,0x00,0x00, // 90 +0x00,0x00,0x00,0x00,0x00,0xCC,0x76,0x36,0x7E,0xD8,0xD8,0x6E,0x00,0x00,0x00,0x00, // 1 +0x00,0x00,0x3E,0x6C,0xCC,0xCC,0xFE,0xCC,0xCC,0xCC,0xCC,0xCE,0x00,0x00,0x00,0x00, // 2 +0x00,0x10,0x38,0x6C,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, // 3 +0x00,0x00,0xC6,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, // 4 +0x00,0x60,0x30,0x18,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, // 5 +0x00,0x30,0x78,0xCC,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, // 6 +0x00,0x60,0x30,0x18,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, // 7 +0x00,0x00,0xC6,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0x78,0x00, // 8 +0x00,0xC6,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, // 9 +0x00,0xC6,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, // a +0x00,0x18,0x18,0x3C,0x66,0x60,0x60,0x60,0x66,0x3C,0x18,0x18,0x00,0x00,0x00,0x00, // b +0x00,0x38,0x6C,0x64,0x60,0xF8,0x60,0x60,0x60,0x60,0xE6,0xFC,0x00,0x00,0x00,0x00, // c +0x00,0x00,0x66,0x66,0x3C,0x18,0x7E,0x18,0x7E,0x18,0x18,0x18,0x00,0x00,0x00,0x00, // d +0x00,0xF8,0xCC,0xCC,0xF8,0xC4,0xCC,0xDE,0xCC,0xCC,0xCC,0xC6,0x00,0x00,0x00,0x00, // e +0x00,0x0E,0x1B,0x18,0x18,0x18,0x7E,0x18,0x18,0x18,0x18,0x18,0xD8,0x70,0x00,0x00, // f + +0x00,0x18,0x30,0x60,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, // a0 +0x00,0x0C,0x18,0x30,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, // 1 +0x00,0x18,0x30,0x60,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, // 2 +0x00,0x18,0x30,0x60,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, // 3 +0x00,0x00,0x76,0xDC,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00, // 4 +0x76,0xDC,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, // 5 +0x00,0x3C,0x6C,0x6C,0x3E,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 6 +0x00,0x38,0x6C,0x6C,0x38,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 7 +0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x60,0xC0,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, // 8 +0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00, // 9 +0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00, // a +0x00,0xC0,0xC0,0xC2,0xC6,0xCC,0x18,0x30,0x60,0xDC,0x86,0x0C,0x18,0x3E,0x00,0x00, // b +0x00,0xC0,0xC0,0xC2,0xC6,0xCC,0x18,0x30,0x66,0xCE,0x9E,0x3E,0x06,0x06,0x00,0x00, // c +0x00,0x00,0x18,0x18,0x00,0x18,0x18,0x18,0x3C,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00, // d +0x00,0x00,0x00,0x00,0x00,0x36,0x6C,0xD8,0x6C,0x36,0x00,0x00,0x00,0x00,0x00,0x00, // e +0x00,0x00,0x00,0x00,0x00,0xD8,0x6C,0x36,0x6C,0xD8,0x00,0x00,0x00,0x00,0x00,0x00, // f + +0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44, // b0 +0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA, // 1 +0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77, // 2 +0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // 3 +0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // 4 +0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // 5 +0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, // 6 +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, // 7 +0x00,0x00,0x00,0x00,0x00,0xF8,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // 8 +0x36,0x36,0x36,0x36,0x36,0xF6,0x06,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, // 9 +0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, // a +0x00,0x00,0x00,0x00,0x00,0xFE,0x06,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, // b +0x36,0x36,0x36,0x36,0x36,0xF6,0x06,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // c +0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // d +0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // e +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // f + +0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // c0 +0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 1 +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // 2 +0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // 3 +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 4 +0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // 5 +0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // 6 +0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, // 7 +0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 8 +0x00,0x00,0x00,0x00,0x00,0x3F,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, // 9 +0x36,0x36,0x36,0x36,0x36,0xF7,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // a +0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xF7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, // b +0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, // c +0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // d +0x36,0x36,0x36,0x36,0x36,0xF7,0x00,0xF7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, // e +0x18,0x18,0x18,0x18,0x18,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // f + +0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // d0 +0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // 1 +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, // 2 +0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 3 +0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 4 +0x00,0x00,0x00,0x00,0x00,0x1F,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // 5 +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, // 6 +0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFF,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, // 7 +0x18,0x18,0x18,0x18,0x18,0xFF,0x18,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // 8 +0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 9 +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // a +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, // b +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, // c +0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, // d +0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, // e +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // f + +0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0xD8,0xD8,0xD8,0xDC,0x76,0x00,0x00,0x00,0x00, // e0 +0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xFC,0xC6,0xC6,0xC6,0xC6,0xDC,0xC0,0xC0,0x00,0x00, // 1 +0x00,0x00,0xFE,0xC6,0xC6,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00, // 2 +0x00,0x00,0x00,0x00,0x00,0xFE,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00, // 3 +0x00,0x00,0xFE,0xC6,0x60,0x30,0x18,0x18,0x30,0x60,0xC6,0xFE,0x00,0x00,0x00,0x00, // 4 +0x00,0x00,0x00,0x00,0x00,0x7E,0xD8,0xD8,0xD8,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00, // 5 +0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0xC0,0x00,0x00,0x00, // 6 +0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00, // 7 +0x00,0x00,0x7E,0x18,0x3C,0x66,0x66,0x66,0x66,0x3C,0x18,0x7E,0x00,0x00,0x00,0x00, // 8 +0x00,0x00,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00, // 9 +0x00,0x00,0x38,0x6C,0xC6,0xC6,0xC6,0x6C,0x6C,0x6C,0x6C,0xEE,0x00,0x00,0x00,0x00, // a +0x00,0x00,0x1E,0x30,0x18,0x0C,0x3E,0x66,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00, // b +0x00,0x00,0x00,0x00,0x00,0x7E,0xDB,0xDB,0xDB,0x7E,0x00,0x00,0x00,0x00,0x00,0x00, // c +0x00,0x00,0x00,0x03,0x06,0x7E,0xDB,0xDB,0xF3,0x7E,0x60,0xC0,0x00,0x00,0x00,0x00, // d +0x00,0x00,0x1C,0x30,0x60,0x60,0x7C,0x60,0x60,0x60,0x30,0x1C,0x00,0x00,0x00,0x00, // e +0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, // f + +0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0xFE,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00, // f0 +0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0xFF,0x00,0x00,0x00,0x00, // 1 +0x00,0x00,0x00,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00,0x7E,0x00,0x00,0x00,0x00, // 2 +0x00,0x00,0x00,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00,0x7E,0x00,0x00,0x00,0x00, // 3 +0x00,0x0E,0x1B,0x1B,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // 4 +0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xD8,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00, // 5 +0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x7E,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00, // 6 +0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00, // 7 +0x00,0x38,0x6C,0x6C,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 8 +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 9 +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // a +0x00,0x0F,0x0C,0x0C,0x0C,0x0C,0x0C,0xEC,0x6C,0x6C,0x3C,0x1C,0x00,0x00,0x00,0x00, // b +0x00,0xD8,0x6C,0x6C,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // c +0x00,0x70,0xD8,0x30,0x60,0xC8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // d +0x00,0x00,0x00,0x00,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x00,0x00,0x00,0x00,0x00, // e +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 // f + }; diff --git a/private/ntos/nthals/haleagle/ppc/pxsiosup.c b/private/ntos/nthals/haleagle/ppc/pxsiosup.c new file mode 100644 index 000000000..1cd1c9789 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxsiosup.c @@ -0,0 +1,1761 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +contains copyrighted material. Use of this file is restricted +by the provisions of a Motorola Software License Agreement. + +Module Name: + + pxsiosup.c + +Abstract: + + The module provides the PCI ISA bridge support. + +Author: + + Jim Wooldridge (jimw@vnet.ibm.com) + + +Revision History: + + +--*/ + + +#include "halp.h" +#include "pxsystyp.h" +#include "eisa.h" +#include "pxsiosup.h" +#include "pxpcisup.h" +#include "pxmemctl.h" +#include "bugcodes.h" + + +#define SioId 0x04848086 // UMC 8886 + +PVOID HalpPciIsaBridgeConfigBase; +extern USHORT Halp8259MaskTable[]; +extern PADAPTER_OBJECT MasterAdapterObject; +VOID HalpUpdate8259(KIRQL Irql); + + + +// +// Define the context structure for use by the interrupt routine. +// + + +typedef BOOLEAN (*PSECONDARY_DISPATCH)( + PVOID InterruptRoutine, + PVOID ServiceContext, + PVOID TrapFrame + ); + +// +// Declare the interrupt structure for profile interrupt +// + +KINTERRUPT HalpProfileInterrupt; + +// +// The following is the interrupt object used for DMA controller interrupts. +// DMA controller interrupts occur when a memory parity error occurs or a +// programming error occurs to the DMA controller. +// + +// +// Declare the interrupt structure for machine checks +// + +KINTERRUPT HalpMachineCheckInterrupt; + +// +// Declare the interrupt structure for the clock interrupt +// + +KINTERRUPT HalpDecrementerInterrupt; + +// +// Map the interrupt controllers priority scheme to NT IRQL values. +// The SIO prioritizes IRQs as follows: +// IRQ0, IRQ1, IRQ8 ... IRQ15, IRQ3, IRQ4 ... IRQ7. +// +// NOTE: The following table must be coordinated with the entries +// in Halp8259MaskTable in PXIRQL.C +// +KIRQL VectorToIrql[16] = { +// IRQL Vector +// ---- ------ + 26, // 0 + 25, // 1 + 24, // 2 + 15, // 3 + 14, // 4 + 13, // 5 + 12, // 6 + 11, // 7 + 23, // 8 + 22, // 9 + 21, // 10 + 20, // 11 + 19, // 12 + 18, // 13 + 17, // 14 + 16 }; // 15 + +KIRQL HalpTranslateVectorToIrql( + IN ULONG Vector + ) +{ // It is assumed that the caller has checked that Vector is valid (0..15) + return VectorToIrql[Vector]; +} + +// +// Add spurious and bogus interrupt counts +// + +#if DBG +ULONG HalpSpuriousInterruptCount = 0; +ULONG HalpBogusInterruptCount = 0; +#endif + + +// +// Define Isa bus interrupt affinity. +// + +KAFFINITY HalpIsaBusAffinity; + + +// +// The following function is called when a machine check occurs. +// + +BOOLEAN +HalpHandleMachineCheck( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ); + +// +// Define save area for ISA adapter objects. +// + +PADAPTER_OBJECT HalpIsaAdapter[8]; + +// +// Define save area for ISA interrupt mask registers +// and level\edge control registers. +// + +USHORT HalpSioInterruptLevel = 0x0000; // Default to edge-sensitive + + + +BOOLEAN +HalpInitializeInterrupts ( + VOID + ) + +/*++ + +Routine Description: + + This routine is called from phase 0 initialization, it initializes the + 8259 interrupt controller ( currently it masks all 8259 interrupts). + + +Arguments: + + None. + +Return Value: + + +--*/ + +{ UCHAR DataByte; + ULONG Vector; + + + // + // Initialize the SIO 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) HalpIoControlBase)->Interrupt1ControlPort0, + DataByte + ); + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Interrupt2ControlPort0, + DataByte + ); + + // + // The second initialization control word sets the interrupt vector to + // 0-15. + // + + DataByte = 0; + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Interrupt1ControlPort1, + DataByte + ); + + DataByte = 0x08; + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Interrupt2ControlPort1, + DataByte + ); + + // + // The third initialization control word set the controls for slave mode. + // The master ICW3 uses bit position and the slave ICW3 uses a numeric. + // + + DataByte = 1 << SLAVE_IRQL_LEVEL; + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Interrupt1ControlPort1, + DataByte + ); + + DataByte = SLAVE_IRQL_LEVEL; + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->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) HalpIoControlBase)->Interrupt1ControlPort1, + DataByte + ); + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Interrupt2ControlPort1, + DataByte + ); + + + + // + // Mask all 8259 interrupts (except the Slave input) + // + + for (Vector=0; Vector<= HIGHEST_8259_VECTOR; Vector++) { + HalpDisableSioInterrupt(Vector + DEVICE_VECTORS); + } + HalpEnableSioInterrupt(SLAVE_IRQL_LEVEL + DEVICE_VECTORS, Latched); + + // + // Reserve the external interrupt vector for exclusive use by the HAL. + // + + PCR->ReservedVectors |= (1 << EXTERNAL_INTERRUPT_VECTOR); + + return TRUE; + +} + + +BOOLEAN +HalpCreateSioStructures ( + VOID + ) + +/*++ + +Routine Description: + + This routine initializes the structures necessary for SIO operations + and connects the intermediate interrupt dispatcher. + +Arguments: + + None. + +Return Value: + + If the second level interrupt dispatcher is connected, then a value of + TRUE is returned. Otherwise, a value of FALSE is returned. + +--*/ + +{ + + UCHAR DataByte; + KIRQL oldIrql; + + + // + // Initialize the Machine Check interrupt handler + // + + if (HalpEnableInterruptHandler(&HalpMachineCheckInterrupt, + HalpHandleMachineCheck, + NULL, + NULL, + MACHINE_CHECK_VECTOR, + MACHINE_CHECK_LEVEL, + MACHINE_CHECK_LEVEL, + Latched, + FALSE, + 0, + FALSE, + InternalUsage, + MACHINE_CHECK_VECTOR + ) == FALSE) { + KeBugCheck(HAL_INITIALIZATION_FAILED); + } + + // + // Enable NMI IOCHK# and PCI SERR# + // + + DataByte = READ_REGISTER_UCHAR(&((PEISA_CONTROL)HalpIoControlBase)->NmiStatus); + WRITE_REGISTER_UCHAR(&((PEISA_CONTROL)HalpIoControlBase)->NmiStatus, + DataByte & ~DISABLE_IOCHK_NMI & ~DISABLE_PCI_SERR_NMI); + + // + // Clear the SIO NMI disable bit. This bit is the high order of the + // NMI enable register. + // + + DataByte = 0; + + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->NmiEnable, + DataByte + ); + + // + // Connect the external interrupt handler + // + + PCR->InterruptRoutine[EXTERNAL_INTERRUPT_VECTOR] = (PKINTERRUPT_ROUTINE) HalpHandleExternalInterrupt; + + // + // register the interrupt vector + // + + HalpRegisterVector(InternalUsage, + EXTERNAL_INTERRUPT_VECTOR, + EXTERNAL_INTERRUPT_VECTOR, + HIGH_LEVEL); + + + + + // Connect directly to the decrementer handler. This is done + // directly rather than thru HalpEnableInterruptHandler due to + // special handling required because the handler calls KdPollBreakIn(). + // + + PCR->InterruptRoutine[DECREMENT_VECTOR] = (PKINTERRUPT_ROUTINE) HalpHandleDecrementerInterrupt; + + + // + // Initialize and connect the Timer 1 interrupt (IRQ0) + // + + if (HalpEnableInterruptHandler( &HalpProfileInterrupt, + (PKSERVICE_ROUTINE) HalpHandleProfileInterrupt, + (PVOID) NULL, + (PKSPIN_LOCK)NULL, + PROFILE_VECTOR, + PROFILE_LEVEL, + PROFILE_LEVEL, + Latched, + TRUE, + 0, + FALSE, + DeviceUsage, + PROFILE_VECTOR + ) == FALSE) { + KeBugCheck(HAL_INITIALIZATION_FAILED); + } + + + // + // Disable Timer 1; only used by profiling + // + + HalDisableSystemInterrupt(PROFILE_VECTOR, PROFILE_LEVEL); + + // + // Set default profile rate + // + + HalSetProfileInterval(5000); + + // + // Raise the IRQL while the SIO interrupt controller is initialized. + // + + KeRaiseIrql(CLOCK2_LEVEL, &oldIrql); + + // + // Initialize any planar registers + // + + HalpInitPlanar(); + + + // + // Enable the clock interrupt + // + HalpUpdateDecrementer(1000); // Get those decrementer ticks going + + + // + // Set ISA bus interrupt affinity. + // + + HalpIsaBusAffinity = PCR->SetMember; + + + // + // Restore IRQL level. + // + + KeLowerIrql(oldIrql); + + + // + // DMA command - set assert level + // + + DataByte = READ_REGISTER_UCHAR(&((PEISA_CONTROL)HalpIoControlBase)->Dma1BasePort.DmaStatus); + WRITE_REGISTER_UCHAR(&((PEISA_CONTROL)HalpIoControlBase)->Dma1BasePort.DmaStatus, + DataByte & ~DACK_ASSERT_HIGH & ~DREQ_ASSERT_LOW); + + // + // 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) HalpIoControlBase)->Dma1BasePort.AllMask, + 0x0F + ); + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Dma2BasePort.AllMask, + 0x0E + ); + + return(TRUE); +} + +BOOLEAN +HalpMapIoControlSpace ( + VOID + ) + +/*++ + +Routine Description: + + This routine maps the HAL SIO control space for a PowerPC system. + +Arguments: + + None. + +Return Value: + + If the initialization is successfully completed, then a value of TRUE + is returned. Otherwise, a value of FALSE is returned. + +--*/ + +{ + + + PHYSICAL_ADDRESS physicalAddress; + + // + // Map SIO control space. + // + + physicalAddress.HighPart = 0; + physicalAddress.LowPart = IO_CONTROL_PHYSICAL_BASE; + HalpIoControlBase = MmMapIoSpace(physicalAddress, + PAGE_SIZE * 16, + FALSE); + + + if (HalpIoControlBase == NULL) + return FALSE; + else + return TRUE; + +} + +BOOLEAN +HalpHandleExternalInterrupt( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext, + IN PVOID TrapFrame + ) + +/*++ + +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 SIO device interrupts. Its function is to call the second + level interrupt dispatch routine and acknowledge the interrupt at the SIO + controller. + + N.B. This routine is entered and left with external interrupts disabled. + + +Arguments: + + Interrupt - Supplies a pointer to the interrupt object. + + ServiceContext - Supplies a pointer to the SIO interrupt acknowledge + register. + + None. + +Return Value: + + Returns the value returned from the second level routine. + +--*/ + +{ + PSECONDARY_DISPATCH SioHandler; + PKINTERRUPT SioInterrupt; + USHORT interruptVector; + BOOLEAN returnValue; + UCHAR OldIrql; + USHORT Isr; + UCHAR Irql; + + + // + // Read the interrupt vector. + // + + interruptVector = READ_REGISTER_UCHAR(HalpInterruptBase); + + // + // check for nmi interrupt before we raise irql since we would raise to a + // bogus level + // + + if (interruptVector == 0xFF) { + + HalpHandleMachineCheck(NULL, NULL); + } + + // + // check for spurious interrupt + // + + if (interruptVector == SPURIOUS_VECTOR) { + + WRITE_REGISTER_UCHAR(&((PEISA_CONTROL)HalpIoControlBase)->Interrupt1ControlPort0, + 0x0B); + Isr = READ_REGISTER_UCHAR(&((PEISA_CONTROL)HalpIoControlBase)->Interrupt1ControlPort0); + if (!(Isr & 0x80)) { + + // + // Spurious interrupt + // + +#if DBG + //DbgPrint("A spurious interrupt occurred. \n"); + HalpSpuriousInterruptCount++; +#endif + return(0); + + } + } + + if (interruptVector > HIGHEST_8259_VECTOR) { +#if DBG + DbgPrint("A bogus interrupt (0x%02x) occurred. \n", interruptVector); + HalpBogusInterruptCount++; +#endif + return (0); + } + + // + // Translate vector to IRQL and raise IRQL + // + + Irql = HalpTranslateVectorToIrql(interruptVector); + KeRaiseIrql( Irql, &OldIrql); + + // + // Dispatch to the secondary interrupt service routine. + // + + SioHandler = (PSECONDARY_DISPATCH) + PCR->InterruptRoutine[DEVICE_VECTORS + interruptVector]; + SioInterrupt = CONTAINING_RECORD(SioHandler, + KINTERRUPT, + DispatchCode[0]); + + returnValue = SioHandler(SioInterrupt, + SioInterrupt->ServiceContext, + TrapFrame + ); + + // + // Dismiss the interrupt in the SIO interrupt controllers. + // + + // + // If this is a cascaded interrupt then the interrupt must be dismissed in + // both controllers. + // + + if (interruptVector & 0x08) { + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Interrupt2ControlPort0, + NONSPECIFIC_END_OF_INTERRUPT + ); + + } + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Interrupt1ControlPort0, + NONSPECIFIC_END_OF_INTERRUPT + ); + + // + // Lower IRQL but disable external interrupts. + // Return to caller with interrupts disabled. + // + + + HalpResetIrqlAfterInterrupt(OldIrql); + + return(returnValue); + +} + +VOID +HalpDisableSioInterrupt( + IN ULONG Vector + ) + +/*++ + +Routine Description: + + This function Disables the SIO interrupt. + +Arguments: + + Vector - Supplies the vector of the ESIA interrupt that is Disabled. + +Return Value: + + None. + +--*/ + +{ USHORT MaskBit, i; + + // + // Calculate the SIO interrupt vector. + // + Vector -= DEVICE_VECTORS; + + if (Vector <= HIGHEST_8259_VECTOR) { + // + // Generate 8259 mask + // + MaskBit = (USHORT) (1 << Vector); + + // + // Set the mask bit in Halp8259MaskTable + // + for (i = 0; i <= 31; i++) { + Halp8259MaskTable[i] |= MaskBit; + } + + // Write new mask values to 8259s + HalpUpdate8259(PCR->CurrentIrql); + } +} + +VOID +HalpIsaMapTransfer( + IN PADAPTER_OBJECT AdapterObject, + IN ULONG Offset, + IN ULONG Length, + IN BOOLEAN WriteToDevice + ) +/*++ + +Routine Description: + + This function programs the SIO DMA controller for a transfer. + +Arguments: + + Adapter - Supplies the DMA adapter object to be programed. + + Offset - Supplies the logical address to use for the transfer. + + Length - Supplies the length of the transfer in bytes. + + WriteToDevice - Indicates the direction of the transfer. + +Return Value: + + None. + +--*/ + +{ + + PUCHAR BytePtr; + UCHAR adapterMode; + UCHAR dataByte; + KIRQL Irql; + + + ASSERT(Offset >= IO_CONTROL_PHYSICAL_BASE); + + adapterMode = AdapterObject->AdapterMode; + + // + // Check to see if this request is for a master I/O card. + // + + if (((PDMA_EISA_MODE) &adapterMode)->RequestMode == CASCADE_REQUEST_MODE) { + + // + // Set the mode, Disable the request and return. + // + + if (AdapterObject->AdapterNumber == 1) { + + // + // This request is for DMA controller 1 + // + + PDMA1_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_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) + ); + + } + + return; + } + // + // Determine the mode based on the transfer direction. + // + + ((PDMA_EISA_MODE) &adapterMode)->TransferType = (UCHAR) (WriteToDevice ? + WRITE_TRANSFER : READ_TRANSFER); + + BytePtr = (PUCHAR) &Offset; + + if (AdapterObject->Width16Bits) { + + // + // If this is a 16 bit transfer then adjust the length and the address + // for the 16 bit DMA mode. + // + + Length >>= 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 = BytePtr[2]; + Offset >>= 1; + BytePtr[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, + BytePtr[0] + ); + + WRITE_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseAddress, + BytePtr[1] + ); + + WRITE_REGISTER_UCHAR( + ((PUCHAR) &((PEISA_CONTROL) HalpIoControlBase)->DmaPageLowPort) + + (ULONG)AdapterObject->PagePort, + BytePtr[2] + ); + + + WRITE_REGISTER_UCHAR( + ((PUCHAR) &((PEISA_CONTROL) HalpIoControlBase)->DmaPageHighPort) + + (ULONG)AdapterObject->PagePort, + BytePtr[3] + ); + + // + // Notify DMA chip of the length to transfer. + // + + WRITE_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount, + (UCHAR) ((Length - 1) & 0xff) + ); + + WRITE_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount, + (UCHAR) ((Length - 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, + BytePtr[0] + ); + + WRITE_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseAddress, + BytePtr[1] + ); + + WRITE_REGISTER_UCHAR( + ((PUCHAR) &((PEISA_CONTROL) HalpIoControlBase)->DmaPageLowPort) + + (ULONG)AdapterObject->PagePort, + BytePtr[2] + ); + + + WRITE_REGISTER_UCHAR( + ((PUCHAR) &((PEISA_CONTROL) HalpIoControlBase)->DmaPageHighPort) + + (ULONG)AdapterObject->PagePort, + BytePtr[3] + ); + + // + // Notify DMA chip of the length to transfer. + // + + WRITE_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount, + (UCHAR) ((Length - 1) & 0xff) + ); + + WRITE_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount, + (UCHAR) ((Length - 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); + +} + +VOID +HalpEnableSioInterrupt( + IN ULONG Vector, + IN KINTERRUPT_MODE InterruptMode + ) + +/*++ + +Routine Description: + + This function enables the SIO interrupt and sets + the level/edge register to the requested value. + +Arguments: + + Vector - Supplies the vector of the interrupt that is enabled. + + InterruptMode - Supplies the mode of the interrupt; LevelSensitive or + Latched. + +Return Value: + + None. + +--*/ + +{ USHORT MaskBit, Irql, i; + + // + // Calculate the SIO interrupt vector. + // + Vector -= DEVICE_VECTORS; + + if (Vector <= HIGHEST_8259_VECTOR) { + // + // Generate 8259 mask + // + MaskBit = (USHORT) ~(1 << Vector); + + + // + // Force interrupts to be latched (edge-triggered) if Big Bend + // + if(HalpSystemType == MOTOROLA_BIG_BEND) + InterruptMode = Latched; + + // + // Set the level/edge control register. + // + if (InterruptMode == LevelSensitive) { + HalpSioInterruptLevel |= ~MaskBit; + } else { + HalpSioInterruptLevel &= MaskBit; + } + + if (Vector & 0x08) { + + // + // The interrupt is in controller 2. + // + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Interrupt2EdgeLevel, + (UCHAR) (HalpSioInterruptLevel >> 8) + ); + + } else { + + // + // The interrupt is in controller 1. + // + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Interrupt1EdgeLevel, + (UCHAR) HalpSioInterruptLevel + ); + } + + + // + // Clear mask bit in Halp8259MaskTable + // + Irql = VectorToIrql[Vector]; + for (i = 0; i < Irql; i++) { + Halp8259MaskTable[i] &= MaskBit; + } + + // Write new mask values to 8259s + HalpUpdate8259(PCR->CurrentIrql); + } +} + +PADAPTER_OBJECT +HalpAllocateIsaAdapter( + IN PDEVICE_DESCRIPTION DeviceDescriptor, + OUT PULONG NumberOfMapRegisters + ) +/*++ + +Routine Description: + + This function allocates an ISA adapter object according to the + specification supplied in the device description. The necessary device + descriptor information is saved. If there is + no existing adapter object for this channel then a new one is allocated. + The saved information in the adapter object is used to set the various DMA + modes when the channel is allocated or a map transfer is done. + +Arguments: + + DeviceDescription - Supplies the description of the device which want to + use the DMA adapter. + + NumberofMapRegisters - number of map registers required for the adapter + object created + + +Return Value: + + Returns a pointer to the newly created adapter object or NULL if one + cannot be created. + +--*/ + +{ + + PADAPTER_OBJECT adapterObject; + PVOID adapterBaseVa; + ULONG channelNumber; + ULONG numberOfMapRegisters; + ULONG controllerNumber; + DMA_EXTENDED_MODE extendedMode; + UCHAR adapterMode; + BOOLEAN useChannel; + ULONG maximumLength; + + // + // Determine if the the channel number is important. Master cards + // do not use a channel number. + // + + + if ((DeviceDescriptor->Master) && (DeviceDescriptor->InterfaceType != Isa)) { + + useChannel = FALSE; + + } else { + + useChannel = TRUE; + } + + // + // Channel 4 cannot be used since it is used for chaining. Return null if + // it is requested. + // + + if ((DeviceDescriptor->DmaChannel == 4 || + DeviceDescriptor->DmaChannel > 7) && useChannel) { + + return(NULL); + } + + // + // Limit the maximum length to 2 GB this is done so that the BYTES_TO_PAGES + // macro works correctly. + // + + maximumLength = DeviceDescriptor->MaximumLength & 0x7fffffff; + + // + // Determine the number of map registers for this device. + // + + if (DeviceDescriptor->ScatterGather && + !(DeviceDescriptor->InterfaceType == Isa && + DeviceDescriptor->Master)) { + + + // + // Scatter gather not supported in SIO + // + + if (!DeviceDescriptor->Master) + + // + // one map register will be required when the the SIO supports this + // + // numberOfMapRegisters = 1; + + return NULL; + + + // + // 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; + + // + // 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 = 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) HalpIoControlBase)->Dma1BasePort; + + } else { + + controllerNumber = 2; + adapterBaseVa = &((PEISA_CONTROL) HalpIoControlBase)->Dma2BasePort; + + } + + // + // Determine if a new adapter object is necessary. If so then allocate it. + // + + if (useChannel && HalpIsaAdapter[DeviceDescriptor->DmaChannel] != NULL) { + + adapterObject = HalpIsaAdapter[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) { + + HalpIsaAdapter[DeviceDescriptor->DmaChannel] = adapterObject; + + } + + // + // Set the maximum number of map registers for this channel bus on + // the number requested and the type of device. + // + + if (numberOfMapRegisters) { + + // + // The specified number of registers are actually allowed to be + // allocated. + // + + adapterObject->MapRegistersPerChannel = numberOfMapRegisters; + + // + // Increase the commitment for the map registers. + // + + if (DeviceDescriptor->Master) { + + // + // Master I/O devices use several sets of map registers double + // their commitment. + // + + MasterAdapterObject->CommittedMapRegisters += + numberOfMapRegisters * 2; + + } else { + + MasterAdapterObject->CommittedMapRegisters += + numberOfMapRegisters; + + } + + // + // If the committed map registers is significantly greater than the + // number allocated then grow the map buffer. + // + + if (MasterAdapterObject->CommittedMapRegisters > + MasterAdapterObject->NumberOfMapRegisters && + MasterAdapterObject->CommittedMapRegisters - + MasterAdapterObject->NumberOfMapRegisters > + MAXIMUM_ISA_MAP_REGISTER ) { + + HalpGrowMapBuffers( + MasterAdapterObject, + INCREMENT_MAP_BUFFER_SIZE + ); + } + + adapterObject->NeedsMapRegisters = TRUE; + + } else { + + // + // No real map registers were allocated. If this is a master + // device, then the device can have as may registers as it wants. + // + + adapterObject->NeedsMapRegisters = FALSE; + + if (DeviceDescriptor->Master) { + + adapterObject->MapRegistersPerChannel = BYTES_TO_PAGES( + maximumLength + ) + + 1; + + } else { + + // + // The device only gets one register. It must call + // IoMapTransfer repeatedly to do a large transfer. + // + + adapterObject->MapRegistersPerChannel = 1; + } + } + } + + adapterObject->ScatterGather = DeviceDescriptor->ScatterGather; + + if (DeviceDescriptor->Master) { + + adapterObject->MasterDevice = TRUE; + + } else { + + adapterObject->MasterDevice = FALSE; + + } + + if (DeviceDescriptor->Master && (DeviceDescriptor->InterfaceType == Isa)) { + + adapterObject->IsaBusMaster = TRUE; + + } else { + + adapterObject->IsaBusMaster = FALSE; + + } + + // + // If the channel number is not used then we are finished. The rest of + // the work deals with channels. + // + + *NumberOfMapRegisters = adapterObject->MapRegistersPerChannel; + + if (!useChannel) { + adapterObject->PagePort = (PVOID) (~0x0); + ((PDMA_EISA_MODE) &adapterMode)->RequestMode = CASCADE_REQUEST_MODE; + return(adapterObject); + } + + // + // Setup the pointers to all the random registers. + // + + adapterObject->ChannelNumber = (UCHAR) channelNumber; + + if (controllerNumber == 1) { + + switch ((UCHAR)channelNumber) { + + case 0: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel0; + break; + + case 1: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel1; + break; + + case 2: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel2; + break; + + case 3: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel3; + break; + } + + // + // Set the adapter number. + // + + adapterObject->AdapterNumber = 1; + + // + // Save the extended mode register address. + // + + adapterBaseVa = + &((PEISA_CONTROL) HalpIoControlBase)->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) HalpIoControlBase)->Dma2ExtendedModePort; + + } + + + adapterObject->Width16Bits = FALSE; + + + // + // Initialize the extended mode port. + // + + *((PUCHAR) &extendedMode) = 0; + extendedMode.ChannelNumber = (UCHAR) channelNumber; + + switch (DeviceDescriptor->DmaSpeed) { + case Compatible: + extendedMode.TimingMode = COMPATIBLITY_TIMING; + break; + + case TypeA: + extendedMode.TimingMode = TYPE_A_TIMING; + break; + + case TypeB: + extendedMode.TimingMode = TYPE_B_TIMING; + break; + + case TypeC: + extendedMode.TimingMode = BURST_TIMING; + break; + + default: + ObDereferenceObject( adapterObject ); + return(NULL); + + } + + switch (DeviceDescriptor->DmaWidth) { + case Width8Bits: + extendedMode.TransferSize = BY_BYTE_8_BITS; + break; + + case Width16Bits: + extendedMode.TransferSize = BY_BYTE_16_BITS; + + // + // Note Width16bits should not be set here because there is no need + // to shift the address and the transfer count. + // + + break; + + default: + ObDereferenceObject( adapterObject ); + return(NULL); + + } + + WRITE_REGISTER_UCHAR( adapterBaseVa, *((PUCHAR) &extendedMode)); + + + // + // Initialize the adapter mode register value to the correct parameters, + // and save them in the adapter object. + // + + adapterMode = 0; + ((PDMA_EISA_MODE) &adapterMode)->Channel = adapterObject->ChannelNumber; + + if (DeviceDescriptor->Master) { + + ((PDMA_EISA_MODE) &adapterMode)->RequestMode = CASCADE_REQUEST_MODE; + + // + // Set the mode, and enable the request. + // + + if (adapterObject->AdapterNumber == 1) { + + // + // This request is for DMA controller 1 + // + + PDMA1_CONTROL dmaControl; + + dmaControl = adapterObject->AdapterBaseVa; + + WRITE_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 2 + // + + 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); +} + +ULONG +HalReadDmaCounter( + IN PADAPTER_OBJECT AdapterObject + ) +/*++ + +Routine Description: + + This function reads the DMA counter and returns the number of bytes left + to be transferred. + +Arguments: + + AdapterObject - Supplies a pointer to the adapter object to be read. + +Return Value: + + Returns the number of bytes still to be transferred. + +--*/ + +{ + ULONG count=0; + 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 +HalpHandleIoError ( + VOID + ) + +{ + + UCHAR StatusByte; + + + // + // Read NMI status + // + + StatusByte = READ_REGISTER_UCHAR(&((PEISA_CONTROL) HalpIoControlBase)->NmiStatus); + + // + // Test for PCI bus error + // + + if (StatusByte & 0x40) { + HalDisplayString ("NMI: IOCHK\n"); + } + + // + // Test for ISA IOCHK + // + + if (StatusByte & 0x80) { + HalDisplayString ("NMI: PCI System Error\n"); + } + +} + + diff --git a/private/ntos/nthals/haleagle/ppc/pxsiosup.h b/private/ntos/nthals/haleagle/ppc/pxsiosup.h new file mode 100644 index 000000000..6b94bdc51 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxsiosup.h @@ -0,0 +1,221 @@ + +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + pxsiosup.h + +Abstract: + + The module defines the structures, and defines for the SIO chip set. + The SIO_CONTROL structure is a superset of the EISA_CONTROL stucture. + Differences from the Eisa control stucture are marked with comments. + +Author: + + Jim Wooldridge + +Revision History: + + +--*/ + +#ifndef _SIO_ +#define _SIO_ + + + + + +BOOLEAN +HalpInitSMCSuperIo ( + VOID + ); + +BOOLEAN +HalpInitNationalSuperIo ( + VOID + ); + +typedef struct _SIO_CONTROL { + DMA1_CONTROL Dma1BasePort; // Offset 0x000 + UCHAR Reserved0[16]; + UCHAR Interrupt1ControlPort0; // Offset 0x020 + UCHAR Interrupt1ControlPort1; // Offset 0x021 + UCHAR Reserved1[32 - 2]; + UCHAR Timer1; // Offset 0x40 + UCHAR RefreshRequest; // Offset 0x41 + UCHAR SpeakerTone; // Offset 0x42 + UCHAR CommandMode1; // Offset 0x43 + UCHAR Reserved14[28]; + UCHAR ResetUbus; // Offset 0x60 + UCHAR NmiStatus; // Offset 0x61 + UCHAR Reserved15[14]; + UCHAR NmiEnable; // Offset 0x70 + UCHAR Reserved16[7]; + UCHAR BiosTimer[4]; // Offset 0x78 + UCHAR Reserved13[4]; + DMA_PAGE DmaPageLowPort; // Offset 0x080 + UCHAR Reserved2; + UCHAR AlternateReset; // Offset 0x092 + UCHAR Reserved17[14]; + UCHAR Interrupt2ControlPort0; // Offset 0x0a0 + UCHAR Interrupt2ControlPort1; // Offset 0x0a1 + UCHAR Reserved3[32-2]; + DMA2_CONTROL Dma2BasePort; // Offset 0x0c0 + UCHAR CoprocessorError; // Offset 0x0f0 + UCHAR Reserved4[0x281]; + UCHAR SecondaryFloppyOutput; // Offset 0x372 + UCHAR Reserved18[0x27]; + UCHAR Reserved21[0x59]; + UCHAR PrimaryFloppyOutput; // Offset 0x3f2 + UCHAR Reserved5[19]; + UCHAR Dma1ExtendedModePort; // Offset 0x40b + UCHAR Reserved6[4]; + UCHAR Channel0ScatterGatherCommand; // Offset 0x410 + UCHAR Channel1ScatterGatherCommand; // Offset 0x411 + UCHAR Channel2ScatterGatherCommand; // Offset 0x412 + UCHAR Channel3ScatterGatherCommand; // Offset 0x413 + UCHAR Reserved19; // Offset 0x414 + UCHAR Channel5ScatterGatherCommand; // Offset 0x415 + UCHAR Channel6ScatterGatherCommand; // Offset 0x416 + UCHAR Channel7ScatterGatherCommand; // Offset 0x417 + UCHAR Channel0ScatterGatherStatus; // Offset 0x418 + UCHAR Channel1ScatterGatherStatus; // Offset 0x419 + UCHAR Channel2ScatterGatherStatus; // Offset 0x41a + UCHAR Channel3ScatterGatherStatus; // Offset 0x41b + UCHAR Reserved20; // Offset 0x41c + UCHAR Channel5ScatterGatherStatus; // Offset 0x41d + UCHAR Channel6ScatterGatherStatus; // Offset 0x41e + UCHAR Channel7ScatterGatherStatus; // Offset 0x41f + UCHAR Channel0ScatterGatherTable[4]; // Offset 0x420 + UCHAR Channel1ScatterGatherTable[4]; // Offset 0x424 + UCHAR Channel2ScatterGatherTable[4]; // Offset 0x428 + UCHAR Channel3ScatterGatherTable[4]; // Offset 0x42c + UCHAR Reserved22[4]; // Offset 0x430 + UCHAR Channel5ScatterGatherTable[4]; // Offset 0x434 + UCHAR Channel6ScatterGatherTable[4]; // Offset 0x438 + UCHAR Channel7ScatterGatherTable[4]; // Offset 0x43c + UCHAR Reserved8[0x40]; + DMA_PAGE DmaPageHighPort; // Offset 0x480 + UCHAR Reserved10[70]; + UCHAR Dma2ExtendedModePort; // Offset 0x4d6 +} SIO_CONTROL, *PSIO_CONTROL; + + + +typedef struct _SIO_CONFIG { + UCHAR VendorId[2]; // Offset 0x00 read-only + UCHAR DeviceId[2]; // Offset 0x02 read-only + UCHAR Command[2]; // Offset 0x04 unused + UCHAR DeviceStatus[2]; // Offset 0x06 + UCHAR RevisionId; // Offset 0x08 read-only + UCHAR Reserved1[0x37]; // Offset 0x09 + UCHAR PciControl; // Offset 0x40 + UCHAR PciArbiterControl; // Offset 0x41 + UCHAR PciArbiterPriorityControl; // Offset 0x42 + UCHAR Reserved2; // Offset 0x43 + UCHAR MemCsControl; // Offset 0x44 + UCHAR MemCsBottomOfHole; // Offset 0x45 + UCHAR MemCsTopOfHole; // Offset 0x46 + UCHAR MemCsTopOfMemory; // Offset 0x47 + UCHAR IsaAddressDecoderControl; // Offset 0x48 + UCHAR IsaAddressDecoderRomEnable; // Offset 0x49 + UCHAR IsaAddressDecoderBottomOfHole; // Offset 0x4a + UCHAR IsaAddressDecoderTopOfHole; // Offset 0x4b + UCHAR IsaControllerRecoveryTimer; // Offset 0x4c + UCHAR IsaClockDivisor; // Offset 0x4d + UCHAR UtilityBusEnableA; // Offset 0x4e + UCHAR UtilityBusEnableB; // Offset 0x4f + UCHAR Reserved3[4]; // Offset 0x50 + UCHAR MemCsAttribute1; // Offset 0x54 + UCHAR MemCsAttribute2; // Offset 0x55 + UCHAR MemCsAttribute3; // Offset 0x56 + UCHAR ScatterGatherBaseAddress; // Offset 0x57 + UCHAR Reserved4[0x8]; // Offset 0x58 + UCHAR PciIrq0RouteControl; // Offset 0x60 + UCHAR PciIrq1RouteControl; // Offset 0x61 + UCHAR PciIrq2RouteControl; // Offset 0x62 + UCHAR PciIrq3RouteControl; // Offset 0x63 + UCHAR Reserved5[0x1C]; // Offset 0x64 + UCHAR BiosTimerBaseAddress[2]; // Offset 0x80 +}SIO_CONFIG, *PSIO_CONFIG; + + +// +// Define constants used by SIO config +// + + +// PCI control register - bit values +#define ENABLE_PCI_POSTED_WRITE_BUFFER 0x04 +#define ENABLE_ISA_MASTER_LINE_BUFFER 0x02 +#define EANBLE_DMA_LINE_BUFFER 0x01 + +// PCI Arbiter contol register - bit values +#define ENABLE_GAT 0x01 + + +// ISA CLock Divisor register - bit values +#define ENABLE_COPROCESSOR_ERROR 0x20 +#define ENABLE_MOUSE_SUPPORT 0x10 +#define RSTDRV 0x08 +#define SYSCLK_DIVISOR 0x00 + +//Utility Bus Chip Select A - bit values +#define ENABLE_RTC 0x01 +#define ENABLE_KEYBOARD 0x02 +#define ENABLE_IDE_DECODE 0x10 + +//Utility Bus Chip Select B - bit values +#define ENABLE_RAM_DECODE 0x80 +#define ENABLE_PORT92 0x40 +#define DISABLE_PARALLEL_PORT 0x30 +#define DISABLE_SERIAL_PORTB 0x0c +#define DISABLE_SERIAL_PORTA 0x03 + +// Interrupt controller - bit values +#define LEVEL_TRIGGERED 0x08 +#define SINGLE_MODE 0x02 + +// NMI status/control - bit values +#define DISABLE_IOCHK_NMI 0x08 +#define DISABLE_PCI_SERR_NMI 0x04 + +// NMI enable - bit values +#define DISABLE_NMI 0x80 + +// DMA command - bit values +#define DACK_ASSERT_HIGH 0x80 +#define DREQ_ASSERT_LOW 0x40 +#endif + +// +// Define 8259 constants +// + +#define SPURIOUS_VECTOR 7 +#define HIGHEST_8259_VECTOR 15 +// +// Define 8254 timer constants +// + +// +// Convert the interval to rollover count for 8254 Timer1 device. +// Since timer1 counts down a 16 bit value at a rate of 1.193M counts-per- +// sec, the computation is: +// RolloverCount = (Interval * 0.0000001) * (1.193 * 1000000) +// = Interval * 0.1193 +// = Interval * 1193 / 10000 +// +// + + + +#define COMMAND_8254_COUNTER0 0x00 // Select count 0 +#define COMMAND_8254_RW_16BIT 0x30 // Read/Write LSB firt then MSB +#define COMMAND_8254_MODE2 0x4 // Use mode 2 +#define COMMAND_8254_BCD 0x0 // Binary count down +#define COMMAND_8254_LATCH_READ 0x0 // Latch read command diff --git a/private/ntos/nthals/haleagle/ppc/pxstall.s b/private/ntos/nthals/haleagle/ppc/pxstall.s new file mode 100644 index 000000000..fd3555c0d --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxstall.s @@ -0,0 +1,326 @@ +//#*********************************************************************** +// +// Copyright 1994 MOTOROLA, INC. All Rights Reserved. This file +// contains copyrighted material. Use of this file is restricted +// by the provisions of a Motorola Software License Agreement. +// +// Copyright 1993 International Buisness Machines Corporation. +// All Rights Reserved. +// +// This file contains copyrighted material. Use of this file is +// restricted by the provisions of a Motorola/IBM Joint Software +// License Agreement. +// +// File Name: +// PXSTALL.S +// +// Functions: +// KeStallExecutionProcessor +// HalpCalibrateStall +// +// History: +// 21-Sep-1993 Steve Johns +// Original Version +// 24-Dec-1993 Peter Johnston +// Adapted to 601 HAL in an attempt to avoid having different +// versions if at all possible. Original was designed for both +// 601 and 603 but had some 601 difficulties. +// 17-Jan-1994 Steve Johns +// Changed to treat 601 vs PowerPC time base differences more +// transparently. +// 11-Sep-1995 Steve Johns +// Removed 601 specific ocde +// Removed 603 workaround, since we don't support < 603 v3.2 +// +//#*********************************************************************** + + + +#include "halppc.h" + +#define ERRATA603 FALSE +#define CMOS_INDEX 0x70 +#define CMOS_DATA 0x71 +#define RTC_SECOND 0x80 + + + .extern HalpPerformanceFrequency + .extern HalpIoControlBase + .extern ..HalpDivide + +// +// Register Definitions +// + .set Microsecs, r.3 + .set TimerLo , r.6 + .set TimerHi , r.7 + .set EndTimerLo, r.3 + .set EndTimerHi, r.4 + .set Temp , r.8 + .set Temp2 , r.9 + .set IO_Base , r.10 + +//#*********************************************************************** +// +// Synopsis: +// VOID KeStallExecutionProcessor( +// ULONG Microseconds) +// +// Purpose: +// This function stalls the execution at least the specified number +// of microseconds, but not substantially longer. +// +// Returns: +// Nothing. +// +// Global Variables Referenced: +// HalpPerformanceFrequency +//#*********************************************************************** + + SPECIAL_ENTRY(KeStallExecutionProcessor) + mflr r.0 // Save Link Register + PROLOGUE_END(KeStallExecutionProcessor) + + cmpli 0,0,Microsecs,0 // if (Microseconds == 0) + beqlr- // return; + +// +// Read START time +// + bl ..HalpReadTB // ReadPerformanceCounter(); + +// +// Get PerformanceCounter frequency +// + lwz Temp,[toc]HalpPerformanceFrequency(r.toc) + lwz Temp,0(Temp) +// +// Compute: (Microseconds * PerformanceFrequency) / 1,000,000 +// + mulhwu. EndTimerHi,Microsecs,Temp + mullw EndTimerLo,Microsecs,Temp + LWI (r.5, 1000000) + bl ..HalpDivide + +// +// Account for software overhead +// + .set Overhead, 30 + cmpwi r.3, Overhead + ble SkipOverhead + addi r.3, r.3, -Overhead // Reduce delay +SkipOverhead: + +// +// Add delay to start time +// + addc EndTimerLo, TimerLo, r.3 + addze EndTimerHi, TimerHi + + + +// +// while (ReadPerformanceCounter() < EndTimer); +// +StallLoop: + bl ..HalpReadTB // Read Time Base + cmpl 0,0,TimerHi,EndTimerHi // Is TimerHi >= EndTimerHi ? + blt- StallLoop // No + bgt+ StallExit // Yes + cmpl 0,0,TimerLo,EndTimerLo // Is TimerLo >= EndTimerLo ? + blt StallLoop // Branch if not + +StallExit: + mtlr r.0 // Restore Link Register + + SPECIAL_EXIT(KeStallExecutionProcessor) + + + + + + +// +// This routine is the ReadPerformanceCounter routine for PowerPC +// architectures (not the 601). +// + LEAF_ENTRY (HalpReadTB) + + mftbu TimerHi // Read the TB registers coherently + mftb TimerLo +#if ERRATA603 + mftb TimerLo + mftb TimerLo + mftb TimerLo +#endif + mftbu Temp + cmpl 0,0,Temp,TimerHi + bne- ..HalpReadTB + + LEAF_EXIT (HalpReadTB) + + + +// +// Returns the number of performance counter ticks/second. +// +// The DECREMENTER is clocked at the same rate as the PowerPC Time Base (TB) +// and the POWER RTC. The POWER RTC is supposed to be clocked at 7.8125 MHz, +// but on early prototypes of the Sandalfoot platform, this is not true). +// In either case, to keep the calibration routine simple and generic, we +// will determine the DECREMENTER clock rate by counting ticks for exactly +// 1 second (as measured against the CMOS RealTimeClock). We then use that +// value in the KeStallExecutionProcessor() and KeQueryPerformanceCounter() +// + + LEAF_ENTRY(HalpCalibrateTB) + + // Get base address of ISA I/O space so we can talk to the CMOS RTC + lwz IO_Base,[toc]HalpIoControlBase(r.toc) + lwz IO_Base,0(IO_Base) + + + li r.3,RTC_SECOND // Read seconds from CMOS RTC + stb r.3,CMOS_INDEX(IO_Base) // Write CMOS index + eieio + lbz r.4,CMOS_DATA(IO_Base) // Read CMOS data + + +WaitForTick1: + li r.3,RTC_SECOND // Read seconds from CMOS RTC + stb r.3,CMOS_INDEX(IO_Base) // Write CMOS index + eieio + lbz r.3,CMOS_DATA(IO_Base) // Read CMOS data + cmpl 0,0,r.3,r.4 // Loop until it changes + beq+ WaitForTick1 + + + li r.4,-1 // Start the decrementer at max. count + mtdec r.4 +#if ERRATA603 + isync +#endif + +WaitForTick2: + li r.4,RTC_SECOND // Read seconds from CMOS RTC + stb r.4,CMOS_INDEX(IO_Base) // Write CMOS index + eieio + lbz r.4,CMOS_DATA(IO_Base) // Read CMOS data + cmpl 0,0,r.3,r.4 + beq+ WaitForTick2 + + mfdec r.3 // Read the decrementer + neg r.3,r.3 // Compute delta ticks + + LEAF_EXIT(HalpCalibrateTB) + + + + LEAF_ENTRY(HalpCalibrateTBPStack) + +#define NVRAM_INDEX_LO 0x74 +#define NVRAM_INDEX_HI 0x75 +#define NVRAM_DATA 0x77 +#define RTC_OFFSET 0x1ff8 +#define RTC_CONTROL 0x0 +#define RTC_SECONDS 0x1 +#define WRITE 0x80 +#define READ 0x40 + +#define SYNCHRONIZE \ + sync; \ + sync; \ + sync + +#define READ_RTC_REG(reg, reg_num_lo, reg_num_hi) \ + stb reg_num_lo,NVRAM_INDEX_LO(r10); \ + stb reg_num_hi,NVRAM_INDEX_HI(r10); \ + SYNCHRONIZE; \ + lbz reg,NVRAM_DATA(r10) + +#define WRITE_RTC_REG(reg, reg_num_lo, reg_num_hi) \ + stb reg_num_lo,NVRAM_INDEX_LO(r10); \ + stb reg_num_hi,NVRAM_INDEX_HI(r10); \ + SYNCHRONIZE; \ + stb reg,NVRAM_DATA(r10); \ + SYNCHRONIZE + +// Here are the steps to getting the Seconds register out of the CMOS RTC +// A. Stop the RTC +// 1. Read control reg +// 2. Set READ bit +// 3. write control reg +// +// B. Read Seconds +// +// C. Restart the RTC +// 1. Read control reg +// 2. Clear READ bit +// 3. write control reg + +#define GET_SECONDS(reg) \ + READ_RTC_REG(r9, r7, r8); \ + ori r9,r9,READ; \ + WRITE_RTC_REG(r9, r7, r8); \ + \ + READ_RTC_REG(reg, r5, r6); \ + \ + READ_RTC_REG(r9, r7, r8); \ + andi. r9,r9,~READ; \ + WRITE_RTC_REG(r9, r7, r8) + + // Get base address of ISA I/O space + // so we can talk to the CMOS RTC + lwz r10,[toc]HalpIoControlBase(r.toc) + lwz r10,0(r10) + + // Set up some offsets into the Real + // Time Clock... + li r5,RTC_OFFSET+RTC_SECONDS // r5 <- Seconds register offset + rlwinm r6,r5,32-8,24,31 // r6 <- Shift > 8 and mask 0xff + li r7,RTC_OFFSET+RTC_CONTROL // r7 <- Control register Offset + rlwinm r8,r7,32-8,24,31 // r8 <- Shift > 8 and mask 0xff + +WaitForRTC.Ps: + READ_RTC_REG(r3, r7, r8) // Read Control register + andi. r3,r3,WRITE // Is it being written to? + bne WaitForRTC.Ps // If so, loop again + GET_SECONDS(r3) // Get RTC seconds register + +WaitForTick0.Ps: + READ_RTC_REG(r4, r7, r8) // Read Control register + andi. r4,r4,WRITE // Is it being written to? + bne WaitForTick0.Ps // If so, loop again + GET_SECONDS(r4) // Get RTC seconds register + cmpw r4,r3 // Loop until it changes + beq WaitForTick0.Ps + + +WaitForTick1.Ps: + READ_RTC_REG(r3, r7, r8) // Read Control register + andi. r3,r3,WRITE // Is it being written to? + bne WaitForTick1.Ps // If so, loop again + GET_SECONDS(r3) // Get RTC seconds register + cmpw r3,r4 // Loop until it changes + beq WaitForTick1.Ps + + li r4,-1 // Start the decrementer at max. count + mtdec r4 +#if ERRATA603 + isync +#endif + +WaitForTick2.Ps: + READ_RTC_REG(r4, r7, r8) // Read Control register + andi. r4,r4,WRITE // Is it being written to? + bne WaitForTick2.Ps // If so, loop again + GET_SECONDS(r4) // Get RTC seconds register + cmpw r4,r3 // Loop until it changes + beq WaitForTick2.Ps + + mfdec r.3 // Read the decrementer + neg r.3,r.3 // Compute delta ticks + + LEAF_EXIT(HalpCalibrateTBPStack) + + diff --git a/private/ntos/nthals/haleagle/ppc/pxsysbus.c b/private/ntos/nthals/haleagle/ppc/pxsysbus.c new file mode 100644 index 000000000..cb3e6c720 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxsysbus.c @@ -0,0 +1,204 @@ +/*++ + + +Copyright (C) 1989-1995 Microsoft Corporation + +Module Name: + + pxsysbus.c + +Abstract: + +Author: + +Environment: + +Revision History: + Jim Wooldridge - IBM + - ported to PowerPC + 9/26/95 Steve Johns - Motorola + - use BusInterruptLevel instead of BusInterruptVector + + +--*/ + +#include "halp.h" + +#include "eisa.h" +#include "pxmemctl.h" +#include "pxsiosup.h" +#include "pxsystyp.h" + +KIRQL HalpTranslateVectorToIrql(IN ULONG Vector); + + +BOOLEAN +HalpTranslateSystemBusAddress( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PHYSICAL_ADDRESS BusAddress, + IN OUT PULONG AddressSpace, + OUT PPHYSICAL_ADDRESS TranslatedAddress + ); + +ULONG +HalpGetSystemInterruptVector( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ); + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE,HalpGetSystemInterruptVector) +#endif + + +BOOLEAN +HalpTranslateSystemBusAddress( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PHYSICAL_ADDRESS BusAddress, + IN OUT PULONG AddressSpace, + OUT PPHYSICAL_ADDRESS TranslatedAddress + ) + +/*++ + +Routine Description: + + This function translates a bus-relative address space and address into + a system physical address. + +Arguments: + + BusAddress - Supplies the bus-relative address + + AddressSpace - Supplies the address space number. + Returns the host address space number. + + AddressSpace == 0 => memory space + AddressSpace == 1 => I/O space + + 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 + +--*/ + +{ + PSUPPORTED_RANGE pRange; + + pRange = NULL; + switch (*AddressSpace) { + case 0: + // verify memory address is within buses memory limits + for (pRange = &BusHandler->BusAddresses->PrefetchMemory; pRange; pRange = pRange->Next) { + if (BusAddress.QuadPart >= pRange->Base && + BusAddress.QuadPart <= pRange->Limit) { + break; + } + } + + if (!pRange) { + for (pRange = &BusHandler->BusAddresses->Memory; pRange; pRange = pRange->Next) { + if (BusAddress.QuadPart >= pRange->Base && + BusAddress.QuadPart <= pRange->Limit) { + break; + } + } + } + + break; + + case 1: + // verify IO address is within buses IO limits + for (pRange = &BusHandler->BusAddresses->IO; pRange; pRange = pRange->Next) { + if (BusAddress.QuadPart >= pRange->Base && + BusAddress.QuadPart <= pRange->Limit) { + break; + } + } + break; + } + + if (pRange) { + TranslatedAddress->QuadPart = BusAddress.QuadPart + pRange->SystemBase; + *AddressSpace = pRange->SystemAddressSpace; + return TRUE; + } + + return FALSE; +} + + +ULONG +HalpGetSystemInterruptVector( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ) + +/*++ + +Routine Description: + +Arguments: + + BusInterruptLevel - Supplies the bus specific interrupt level. + + BusInterruptVector - Supplies the bus specific interrupt vector. + + Irql - Returns the system request priority. + + Affinity - Returns the system wide irq affinity. + +Return Value: + + Returns the system interrupt vector corresponding to the specified device. + +--*/ +{ + + UNREFERENCED_PARAMETER( BusHandler ); + UNREFERENCED_PARAMETER( RootHandler ); + UNREFERENCED_PARAMETER( BusInterruptVector ); + + + if (BusInterruptLevel > HIGHEST_8259_VECTOR) { + // + // Invalid BusInterruptLevel, so return Affinity of 0x0000; + // + *Affinity = 0; + return(DEVICE_VECTORS); + + } else { + + *Affinity = 1; + + // + // Translate BusInterruptLevel to IRQL + // + *Irql = HalpTranslateVectorToIrql(BusInterruptLevel); + + // + // The vector is equal to the specified bus level + DEVICE_VECTORS. + // + return(BusInterruptLevel + DEVICE_VECTORS); + + } +} + diff --git a/private/ntos/nthals/haleagle/ppc/pxsysint.c b/private/ntos/nthals/haleagle/ppc/pxsysint.c new file mode 100644 index 000000000..b02a11ca7 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxsysint.c @@ -0,0 +1,214 @@ +/*++ + +Copyright (c) 1991-1993 Microsoft Corporation + +Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +contains copyrighted material. Use of this file is restricted +by the provisions of a Motorola Software License Agreement. + +Module Name: + + pxsysint.c + +Abstract: + + This module implements the HAL enable/disable system interrupt, and + request interprocessor interrupt routines for a Power PC. + + + +Author: + + David N. Cutler (davec) 6-May-1991 + +Environment: + + Kernel mode + +Revision History: + + Jim Wooldridge + + Removed internal interrupt support + Changed irql mapping + Removed internal bus support + Removed EISA, added PCI, PCMCIA, and ISA bus support + + Steve Johns + Changed to support Timer 1 as profile interrupt + Added HalAcknowledgeIpi +--*/ + +#include "halp.h" + + +VOID +HalDisableSystemInterrupt ( + IN ULONG Vector, + IN KIRQL Irql + ) + +/*++ + +Routine Description: + + This routine disables the specified system interrupt. + +Arguments: + + Vector - Supplies the vector of the system interrupt that is disabled. + + Irql - Supplies the IRQL of the interrupting source. + +Return Value: + + None. + +--*/ + +{ + + KIRQL OldIrql; + + // + // Raise IRQL to the highest level and acquire device enable spinlock. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + KiAcquireSpinLock(&HalpSystemInterruptLock); + + + // + // If the vector number is within the range of the EISA interrupts, then + // disable the EISA interrupt. + // + + if (Vector >= DEVICE_VECTORS && Vector < DEVICE_VECTORS + MAXIMUM_DEVICE_VECTOR ) { + HalpDisableSioInterrupt(Vector); + } + + // + // Release the device enable spin lock and lower IRQL to the previous level. + // + + KiReleaseSpinLock(&HalpSystemInterruptLock); + KeLowerIrql(OldIrql); + return; +} + +BOOLEAN +HalEnableSystemInterrupt ( + IN ULONG Vector, + IN KIRQL Irql, + IN KINTERRUPT_MODE InterruptMode + ) + +/*++ + +Routine Description: + + This routine enables the specified system interrupt. + +Arguments: + + Vector - Supplies the vector of the system interrupt that is enabled. + + Irql - Supplies the IRQL of the interrupting source. + + InterruptMode - Supplies the mode of the interrupt; LevelSensitive or + Latched. + +Return Value: + + TRUE if the system interrupt was enabled + +--*/ + +{ + + KIRQL OldIrql; + + // + // Raise IRQL to the highest level and acquire device enable spinlock. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + KiAcquireSpinLock(&HalpSystemInterruptLock); + + // + // If the vector number is within the range of the EISA interrupts, then + // enable the EISA interrupt and set the Level/Edge register. + // + + if (Vector >= DEVICE_VECTORS && Vector < DEVICE_VECTORS + MAXIMUM_DEVICE_VECTOR ) { + HalpEnableSioInterrupt( Vector, InterruptMode); + } + + // + // Release the device enable spin lock and lower IRQL to the previous level. + // + + KiReleaseSpinLock(&HalpSystemInterruptLock); + KeLowerIrql(OldIrql); + return TRUE; +} + +VOID +HalRequestIpi ( + IN ULONG Mask + ) + +/*++ + +Routine Description: + + This routine requests an interprocessor interrupt on a set of processors. + + N.B. This routine must ensure that the interrupt is posted at the target + processor(s) before returning. + +Arguments: + + Mask - Supplies the set of processors that are sent an interprocessor + interrupt. + +Return Value: + + None. + +--*/ + +{ + + // + // Request an interprocessor interrupt on each of the specified target + // processors. + // + + + return; +} + +BOOLEAN +HalAcknowledgeIpi (VOID) + +/*++ + +Routine Description: + + This routine aknowledges an interprocessor interrupt on a set of + processors. + +Arguments: + + None + +Return Value: + + TRUE if the IPI is valid; otherwise FALSE is returned. + +--*/ + +{ + return (TRUE); +} diff --git a/private/ntos/nthals/haleagle/ppc/pxsystyp.c b/private/ntos/nthals/haleagle/ppc/pxsystyp.c new file mode 100644 index 000000000..a35666f81 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxsystyp.c @@ -0,0 +1,96 @@ +//++ +// +// Copyright (c) 1994, 1995 MOTOROLA, INC. All Rights Reserved. This file +// contains copyrighted material. Use of this file is restricted +// by the provisions of a Motorola Software License Agreement. +// +// Module Name: +// +// pxsystyp.c +// +// Abstract: +// +// Add a global variable to indicate which system implementation we are +// running on. Called early in phase 0 init. +// +// Author: +// +// Bill Jones 12/94 +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// +//-- + + +#include "halp.h" +#include "fwstatus.h" +#include "arc.h" +#include "pxsystyp.h" +#include "fwnvr.h" + +SYSTEM_TYPE HalpSystemType = SYSTEM_UNKNOWN; +extern NVR_SYSTEM_TYPE nvr_system_type; + +extern ULONG HalpPciConfigSlot[]; +ULONG HalpPciPowerStack[] = { 0x0800, + 0x1000, + 0x2000, + 0x4000, + 0x10000, + 0x20000, + 0x40000, + 0x80000, + 0x8000 + }; + +BOOLEAN +HalpSetSystemType( PLOADER_PARAMETER_BLOCK LoaderBlock ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT,HalpSetSystemType) +#endif + +BOOLEAN +HalpSetSystemType( PLOADER_PARAMETER_BLOCK LoaderBlock ) +{ + PCONFIGURATION_COMPONENT_DATA ConfigurationEntry; + ULONG MatchKey; + + MatchKey = 0; + ConfigurationEntry=KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot, + SystemClass, + ArcSystem, + &MatchKey); + + if (ConfigurationEntry != NULL) { + + +#if DBG + //DbgPrint("HAL: System configuration = %s\n",ConfigurationEntry->ComponentEntry.Identifier); +#endif + + if (!strcmp(ConfigurationEntry->ComponentEntry.Identifier,"MOTOROLA-Big Bend")) { + HalpSystemType = MOTOROLA_BIG_BEND; + nvr_system_type = nvr_systype_bigbend; + + } else { + // + // Assume it is a PowerStack or OEM'ed PowerStack + // + // + HalpSystemType = MOTOROLA_POWERSTACK; + nvr_system_type = nvr_systype_powerstack; + // + // Change PCI addresses for Blackhawk + // to support other PCI video boards. + // + memcpy(HalpPciConfigSlot, HalpPciPowerStack, sizeof(HalpPciPowerStack)); + + } + } + return TRUE; +} diff --git a/private/ntos/nthals/haleagle/ppc/pxsystyp.h b/private/ntos/nthals/haleagle/ppc/pxsystyp.h new file mode 100644 index 000000000..f58fdcbf5 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxsystyp.h @@ -0,0 +1,44 @@ +//++ +// +// Copyright (c) 1993 IBM Corporation +// +// Copyright (c) 1994, 1995 MOTOROLA, INC. All Rights Reserved. This file +// contains copyrighted material. Use of this file is restricted +// by the provisions of a Motorola Software License Agreement. +// +// Module Name: +// +// pxsystyp.h +// +// Abstract: +// +// Add a global variable to indicate which system implementation we are +// running on. Called early in phase 0 init. +// +// Author: +// +// Bill Jones 12/94 +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// +//-- + + + +BOOLEAN +HalpSetSystemType( PLOADER_PARAMETER_BLOCK LoaderBlock ); + + + +typedef enum { + MOTOROLA_BIG_BEND = 0, + MOTOROLA_POWERSTACK, + SYSTEM_UNKNOWN = 255 +} SYSTEM_TYPE; + + +extern SYSTEM_TYPE HalpSystemType; diff --git a/private/ntos/nthals/haleagle/ppc/pxtime.c b/private/ntos/nthals/haleagle/ppc/pxtime.c new file mode 100644 index 000000000..7d18eb667 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxtime.c @@ -0,0 +1,137 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +contains copyrighted material. Use of this file is restricted +by the provisions of a Motorola Software License Agreement. + +Module Name: + + pxtime.c + +Abstract: + + This module implements the HAL set/query realtime clock routines for + a PowerPC system. + +Author: + + David N. Cutler (davec) 5-May-1991 + +Environment: + + Kernel mode + + +--*/ + +#include "halp.h" +#include "pxsystyp.h" + +BOOLEAN +HalQueryRealTimeClockMk ( + OUT PTIME_FIELDS TimeFields + ); +BOOLEAN +HalSetRealTimeClockMk ( + OUT PTIME_FIELDS TimeFields + ); +BOOLEAN +HalQueryRealTimeClockDs ( + OUT PTIME_FIELDS TimeFields + ); +BOOLEAN +HalSetRealTimeClockDs ( + OUT PTIME_FIELDS TimeFields + ); + + + +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. + +--*/ + +{ + switch (HalpSystemType) { + + break; + + case MOTOROLA_POWERSTACK: + return HalQueryRealTimeClockMk(TimeFields); + break; + + case SYSTEM_UNKNOWN: + case MOTOROLA_BIG_BEND: + default: + return HalQueryRealTimeClockDs(TimeFields); + break; + } +} + +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. + +--*/ + +{ + switch (HalpSystemType) { + + break; + + case MOTOROLA_POWERSTACK: + return HalSetRealTimeClockMk(TimeFields); + break; + + case SYSTEM_UNKNOWN: + case MOTOROLA_BIG_BEND: + default: + return HalSetRealTimeClockDs(TimeFields); + break; + } +} diff --git a/private/ntos/nthals/haleagle/ppc/pxusage.c b/private/ntos/nthals/haleagle/ppc/pxusage.c new file mode 100644 index 000000000..4a9fbf1f3 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxusage.c @@ -0,0 +1,503 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + pxusage.c + +Abstract: + +Author: + + Ken Reneris (kenr) + +Environment: + + Kernel mode only. + +Revision History: + + Jim Wooldridge Ported to PowerPC + +--*/ + +#include "halp.h" + + +// +// Array to remember hal's IDT usage +// + +extern ADDRESS_USAGE *HalpAddressUsageList; +extern IDTUsage HalpIDTUsage[MAXIMUM_IDTVECTOR]; + +KAFFINITY HalpActiveProcessors; + +VOID +HalpGetResourceSortValue ( + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR pRCurLoc, + OUT PULONG sortscale, + OUT PLARGE_INTEGER sortvalue + ); + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT,HalpEnableInterruptHandler) +#pragma alloc_text(INIT,HalpRegisterVector) +#pragma alloc_text(INIT,HalpGetResourceSortValue) +#pragma alloc_text(INIT,HalpReportResourceUsage) +#endif + + + + +BOOLEAN +HalpEnableInterruptHandler ( + IN PKINTERRUPT Interrupt, + IN PKSERVICE_ROUTINE ServiceRoutine, + IN PVOID ServiceContext, + IN PKSPIN_LOCK SpinLock OPTIONAL, + IN ULONG Vector, + IN KIRQL Irql, + IN KIRQL SynchronizeIrql, + IN KINTERRUPT_MODE InterruptMode, + IN BOOLEAN ShareVector, + IN CCHAR ProcessorNumber, + IN BOOLEAN FloatingSave, + IN UCHAR ReportFlags, + IN KIRQL BusVector + ) +/*++ + +Routine Description: + + This function connects & registers an IDT vectors usage by the HAL. + +Arguments: + +Return Value: + +--*/ +{ + // + // Remember which vector the hal is connecting so it can be reported + // later on + // + + + KeInitializeInterrupt( Interrupt, + ServiceRoutine, + ServiceContext, + SpinLock, + Vector, + Irql, + SynchronizeIrql, + InterruptMode, + ShareVector, + ProcessorNumber, + FloatingSave + ); + + // + // Don't fail if the interrupt cannot be connected. + // + + if (!KeConnectInterrupt( Interrupt )) { + + return(FALSE); + } + + HalpRegisterVector (ReportFlags, BusVector, Vector, Irql); + + + // + // Connect the IDT and enable the vector now + // + + return(TRUE); + + +} + + + +VOID +HalpRegisterVector ( + IN UCHAR ReportFlags, + IN ULONG BusInterruptVector, + IN ULONG SystemInterruptVector, + IN KIRQL SystemIrql + ) +/*++ + +Routine Description: + + This registers an IDT vectors usage by the HAL. + +Arguments: + +Return Value: + +--*/ +{ +#if DBG + // There are only 0ff IDT entries... + ASSERT (SystemInterruptVector <= MAXIMUM_IDTVECTOR && + BusInterruptVector <= MAXIMUM_IDTVECTOR); +#endif + + // + // Remember which vector the hal is connecting so it can be reported + // later on + // + + HalpIDTUsage[SystemInterruptVector].Flags = ReportFlags; + HalpIDTUsage[SystemInterruptVector].Irql = SystemIrql; + HalpIDTUsage[SystemInterruptVector].BusReleativeVector = (UCHAR) BusInterruptVector; +} + + +VOID +HalpGetResourceSortValue ( + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR pRCurLoc, + OUT PULONG sortscale, + OUT PLARGE_INTEGER sortvalue + ) +/*++ + +Routine Description: + + Used by HalpReportResourceUsage in order to properly sort + partial_resource_descriptors. + +Arguments: + + pRCurLoc - resource descriptor + +Return Value: + + sortscale - scaling of resource descriptor for sorting + sortvalue - value to sort on + + +--*/ +{ + switch (pRCurLoc->Type) { + case CmResourceTypeInterrupt: + *sortscale = 0; + *sortvalue = RtlConvertUlongToLargeInteger( + pRCurLoc->u.Interrupt.Level ); + break; + + case CmResourceTypePort: + *sortscale = 1; + *sortvalue = pRCurLoc->u.Port.Start; + break; + + case CmResourceTypeMemory: + *sortscale = 2; + *sortvalue = pRCurLoc->u.Memory.Start; + break; + + default: + *sortscale = 4; + *sortvalue = RtlConvertUlongToLargeInteger (0); + break; + } +} + + +VOID +HalpReportResourceUsage ( + IN PUNICODE_STRING HalName, + IN INTERFACE_TYPE DeviceInterfaceToUse + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + PCM_RESOURCE_LIST RawResourceList, TranslatedResourceList; + PCM_FULL_RESOURCE_DESCRIPTOR pRFullDesc, pTFullDesc; + PCM_PARTIAL_RESOURCE_LIST pRPartList=NULL, pTPartList=NULL; + PCM_PARTIAL_RESOURCE_DESCRIPTOR pRCurLoc, pTCurLoc; + PCM_PARTIAL_RESOURCE_DESCRIPTOR pRSortLoc, pTSortLoc; + CM_PARTIAL_RESOURCE_DESCRIPTOR RPartialDesc, TPartialDesc; + ULONG i, j, k, ListSize, Count; + ULONG curscale, sortscale; + UCHAR pass, reporton; + INTERFACE_TYPE interfacetype; + ULONG CurrentIDT, CurrentElement; + ADDRESS_USAGE *CurrentAddress; + LARGE_INTEGER curvalue, sortvalue; + + + // + // Allocate some space to build the resource structure + // + + RawResourceList = (PCM_RESOURCE_LIST) ExAllocatePool (NonPagedPool, PAGE_SIZE*2); + TranslatedResourceList = (PCM_RESOURCE_LIST) ExAllocatePool (NonPagedPool, PAGE_SIZE*2); + + // This functions assumes unset fields are zero + RtlZeroMemory (RawResourceList, PAGE_SIZE*2); + RtlZeroMemory (TranslatedResourceList, PAGE_SIZE*2); + + // + // Initialize the lists + // + + RawResourceList->List[0].InterfaceType = (INTERFACE_TYPE) -1; + + pRFullDesc = RawResourceList->List; + pRCurLoc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) RawResourceList->List; + pTCurLoc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) TranslatedResourceList->List; + + + for(i=0; i < DEVICE_VECTORS; i++) { + if (!(HalpIDTUsage[i].Flags & IDTOwned)) { + HalpIDTUsage[i].Flags = InternalUsage; + HalpIDTUsage[i].BusReleativeVector = (UCHAR) i; + } + } + + for(pass=0; pass < 2; pass++) { + if (pass == 0) { + // + // First pass - build resource lists for resources reported + // reported against device usage. + // + + reporton = DeviceUsage & ~IDTOwned; + interfacetype = DeviceInterfaceToUse; + } else { + + // + // Second pass = build reousce lists for resources reported + // as internal usage. + // + + reporton = InternalUsage & ~IDTOwned; + interfacetype = Internal; + } + + CurrentIDT = 0; + CurrentElement = 0; + CurrentAddress = HalpAddressUsageList; + + for (; ;) { + if (CurrentIDT <= MAXIMUM_IDTVECTOR) { + // + // Check to see if CurrentIDT needs to be reported + // + + if (!(HalpIDTUsage[CurrentIDT].Flags & reporton)) { + // Don't report on this one + CurrentIDT++; + continue; + } + + // + // Report CurrentIDT resource + // + + RPartialDesc.Type = CmResourceTypeInterrupt; + RPartialDesc.ShareDisposition = CmResourceShareDriverExclusive; + RPartialDesc.Flags = + HalpIDTUsage[CurrentIDT].Flags & InterruptLatched ? + CM_RESOURCE_INTERRUPT_LATCHED : + CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; + RPartialDesc.u.Interrupt.Vector = HalpIDTUsage[CurrentIDT].BusReleativeVector; + RPartialDesc.u.Interrupt.Level = HalpIDTUsage[CurrentIDT].BusReleativeVector; + RPartialDesc.u.Interrupt.Affinity = HalpActiveProcessors; + + RtlCopyMemory (&TPartialDesc, &RPartialDesc, sizeof TPartialDesc); + TPartialDesc.u.Interrupt.Vector = CurrentIDT; + TPartialDesc.u.Interrupt.Level = HalpIDTUsage[CurrentIDT].Irql; + + CurrentIDT++; + + } else { + // + // Check to see if CurrentAddress needs to be reported + // + + if (!CurrentAddress) { + break; // No addresses left + } + + if (!(CurrentAddress->Flags & reporton)) { + // Don't report on this list + CurrentElement = 0; + CurrentAddress = CurrentAddress->Next; + continue; + } + + if (!CurrentAddress->Element[CurrentElement].Length) { + // End of current list, go to next list + CurrentElement = 0; + CurrentAddress = CurrentAddress->Next; + continue; + } + + // + // Report CurrentAddress + // + + RPartialDesc.Type = (UCHAR) CurrentAddress->Type; + RPartialDesc.ShareDisposition = CmResourceShareDriverExclusive; + + if (RPartialDesc.Type == CmResourceTypePort) { + i = 1; // address space port + RPartialDesc.Flags = CM_RESOURCE_PORT_IO; + } else { + i = 0; // address space memory + RPartialDesc.Flags = CM_RESOURCE_MEMORY_READ_WRITE; + } + + // Notice: assuming u.Memory and u.Port have the same layout + RPartialDesc.u.Memory.Start.HighPart = 0; + RPartialDesc.u.Memory.Start.LowPart = + CurrentAddress->Element[CurrentElement].Start; + + RPartialDesc.u.Memory.Length = + CurrentAddress->Element[CurrentElement].Length; + + // translated address = Raw address + RtlCopyMemory (&TPartialDesc, &RPartialDesc, sizeof TPartialDesc); + HalTranslateBusAddress ( + interfacetype, // device bus or internal + 0, // bus number + RPartialDesc.u.Memory.Start, // source address + &i, // address space + &TPartialDesc.u.Memory.Start ); // translated address + + if (RPartialDesc.Type == CmResourceTypePort && i == 0) { + TPartialDesc.Flags = CM_RESOURCE_PORT_MEMORY; + } + + CurrentElement++; + } + + // + // Include the current resource in the HALs list + // + + if (pRFullDesc->InterfaceType != interfacetype) { + // + // Interface type changed, add another full section + // + + RawResourceList->Count++; + TranslatedResourceList->Count++; + + pRFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR) pRCurLoc; + pTFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR) pTCurLoc; + + pRFullDesc->InterfaceType = interfacetype; + pTFullDesc->InterfaceType = interfacetype; + + pRPartList = &pRFullDesc->PartialResourceList; + pTPartList = &pTFullDesc->PartialResourceList; + + // + // Bump current location pointers up + // + pRCurLoc = pRFullDesc->PartialResourceList.PartialDescriptors; + pTCurLoc = pTFullDesc->PartialResourceList.PartialDescriptors; + } + + + ASSERT(pRPartList != NULL); + ASSERT(pTPartList != NULL); + + if(pRPartList) pRPartList->Count++; + if(pTPartList) pTPartList->Count++; + + RtlCopyMemory (pRCurLoc, &RPartialDesc, sizeof RPartialDesc); + RtlCopyMemory (pTCurLoc, &TPartialDesc, sizeof TPartialDesc); + + pRCurLoc++; + pTCurLoc++; + } + } + + ListSize = (ULONG) ( ((PUCHAR) pRCurLoc) - ((PUCHAR) RawResourceList) ); + + // + // The HAL's resource usage structures have been built + // Sort the partial lists based on the Raw resource values + // + + pRFullDesc = RawResourceList->List; + pTFullDesc = TranslatedResourceList->List; + + for (i=0; i < RawResourceList->Count; i++) { + + pRCurLoc = pRFullDesc->PartialResourceList.PartialDescriptors; + pTCurLoc = pTFullDesc->PartialResourceList.PartialDescriptors; + Count = pRFullDesc->PartialResourceList.Count; + + for (j=0; j < Count; j++) { + HalpGetResourceSortValue (pRCurLoc, &curscale, &curvalue); + + pRSortLoc = pRCurLoc; + pTSortLoc = pTCurLoc; + + for (k=j; k < Count; k++) { + HalpGetResourceSortValue (pRSortLoc, &sortscale, &sortvalue); + + if (sortscale < curscale || + (sortscale == curscale && + RtlLargeIntegerLessThan (sortvalue, curvalue)) ) { + + // + // Swap the elements.. + // + + RtlCopyMemory (&RPartialDesc, pRCurLoc, sizeof RPartialDesc); + RtlCopyMemory (pRCurLoc, pRSortLoc, sizeof RPartialDesc); + RtlCopyMemory (pRSortLoc, &RPartialDesc, sizeof RPartialDesc); + + // swap translated descriptor as well + RtlCopyMemory (&TPartialDesc, pTCurLoc, sizeof TPartialDesc); + RtlCopyMemory (pTCurLoc, pTSortLoc, sizeof TPartialDesc); + RtlCopyMemory (pTSortLoc, &TPartialDesc, sizeof TPartialDesc); + + // get new curscale & curvalue + HalpGetResourceSortValue (pRCurLoc, &curscale, &curvalue); + } + + pRSortLoc++; + pTSortLoc++; + } + + pRCurLoc++; + pTCurLoc++; + } + + pRFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR) pRCurLoc; + pTFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR) pTCurLoc; + } + + + // + // Inform the IO system of our resources.. + // + + IoReportHalResourceUsage ( + HalName, + RawResourceList, + TranslatedResourceList, + ListSize + ); + + ExFreePool (RawResourceList); + ExFreePool (TranslatedResourceList); +} diff --git a/private/ntos/nthals/haleagle/ppc/sysbios.c b/private/ntos/nthals/haleagle/ppc/sysbios.c new file mode 100644 index 000000000..9aa6dc90c --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/sysbios.c @@ -0,0 +1,73 @@ +/*++ + + +Copyright (C) 1996 Motorola Inc. + +Module Name: + + sysbios.c + +Abstract: + + Emulate System BIOS functions. + +Author: + + Scott Geranen + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#include "halp.h" +#include "pci.h" +#include "pcip.h" +#include "emulate.h" +#include "sysbios.h" +#include "pcibios.h" + +BOOLEAN +HalpEmulateSystemBios( + IN OUT PRXM_CONTEXT P, + IN ULONG Number + ) +/*++ + +Routine Description: + + This function emulates a system BIOS. However, this is really + intended to support video bios functions, not all system BIOS + functions are implemented. + +Arguments: + + P - Supplies a pointer to an emulator context structure. + Number - interrupt number used to enter + +Return Value: + + TRUE = the function was emulated + FALSE = the function was not emulated + +--*/ +{ + switch (Number) { + case 0x1A: + if (P->Gpr[EAX].Xh == PCIBIOS_PCI_FUNCTION_ID) { + return HalpEmulatePciBios(P); + } + + // + // Fall into the default case. + // + + default: + return FALSE; // not supported + } +} + diff --git a/private/ntos/nthals/haleagle/ppc/sysbios.h b/private/ntos/nthals/haleagle/ppc/sysbios.h new file mode 100644 index 000000000..6119bc2d0 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/sysbios.h @@ -0,0 +1,31 @@ +/*++ BUILD Version: 0000 // Increment this if a change has global effects + +Copyright (c) 1996 Motorola Inc. + +Module Name: + + sysbios.h + +Abstract: + + This module contains the private header file for the system BIOS + emulation. + +Author: + + Scott Geranen (3-4-96) + +Revision History: + +--*/ + +#ifndef _SYSBIOS_ +#define _SYSBIOS_ + +BOOLEAN +HalpEmulateSystemBios( + IN OUT PRXM_CONTEXT P, + IN ULONG Number + ); + +#endif // _SYSBIOS_ diff --git a/private/ntos/nthals/haleagle/ppc/txtpalet.h b/private/ntos/nthals/haleagle/ppc/txtpalet.h new file mode 100644 index 000000000..307464362 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/txtpalet.h @@ -0,0 +1,97 @@ +/****************************************************************************** + +txtpalet.h + + Author: Jess Botts + + This file contains the text mode palette. Most of the entries are 0 + because they are not used. The first 8 entries are used for all + background colors and normal intensity foregound colors. Background + colors are displayed at normal intensity only. The 8 entries that + begin at the 56th entry are used for high intensity foreground colors. + + Each entry consists of 3 values, 1 for each color gun. + +******************************************************************************/ + +UCHAR + TextPalette[] = + { /* + Line + R G B R G B R G B R G B Index + */ + +// all background colors and normal intensity foregound colors + + 0, 0, 0, 0, 0, 32, 0, 32, 0, 0, 32, 32, // 0 + 32, 0, 0, 32, 0, 32, 32, 32, 0, 32, 32, 32, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +// high intensity foreground colors + + 16, 16, 16, 0, 0, 63, 0, 63, 0, 0, 63, 63, // 56 + 63, 0, 0, 63, 0, 63, 63, 63, 0, 63, 63, 63, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 64 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 128 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 192 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + +/*****************************************************************************/ diff --git a/private/ntos/nthals/haleagle/ppc/x86bios.c b/private/ntos/nthals/haleagle/ppc/x86bios.c new file mode 100644 index 000000000..1002fae70 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/x86bios.c @@ -0,0 +1,1156 @@ +/*++ + +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: + + 9/26/95 Steve Johns - Motorola + - Don't scan last PCI slot if PowerStack + - Don't execute PCI ROM if BaseClass indicates not video + + 3/29/96 Scott Geranen - Motorola + - call PCI BIOS with bus/dev/func arguments +--*/ + + +#define USE_BIOS_EMULATOR + + + +#include "halp.h" +#include "xm86.h" +#include "x86new.h" +#include "pxpcisup.h" +#include "pxsystyp.h" +#include "pci.h" + +extern ULONG HalpPciMaxSlots; +extern ULONG HalpPciConfigSize; +// +// Define global data. +// + +ULONG HalpX86BiosInitialized = FALSE; +ULONG HalpEnableInt10Calls = FALSE; +PVOID HalpIoMemoryBase = NULL; +PUCHAR HalpRomBase = NULL; + +UCHAR HalpVideoBus; // Used as arguments to the PCI BIOS +UCHAR HalpVideoDevice; // init function. Set HalpInitX86Emulator, +UCHAR HalpVideoFunction; // used by HalpInitializeX86DisplayAdapter. + +UCHAR HalpLastPciBus; // Set by scanning the configuration data and + // used by PCI BIOS eumulation code. + +// +// The MPC105 and the IBM27-82660 map the device number to the AD +// line differently. This value is used to compensate for the +// difference. Any HAL #including this file should set this value +// appropriately. Note that this value is subtracted from the +// computed AD line. +// +#ifndef PCI_DEVICE_NUMBER_OFFSET +#define PCI_DEVICE_NUMBER_OFFSET 0 // default value for eagle +#endif + +ULONG ROM_Length; +#define BUFFER_SIZE (64*1024) +UCHAR ROM_Buffer[BUFFER_SIZE]; + + +BOOLEAN HalpInitX86Emulator( + VOID) + +{ +ULONG ROM_size = 0; +PHYSICAL_ADDRESS PhysAddr; +USHORT Cmd, VendorID; +ULONG Slot, EndSlot; +PVOID HalpVideoConfigBase; +PUCHAR ROM_Ptr, ROM_Shadow; +ULONG i; +UCHAR BaseClass; + + + PhysAddr.HighPart = 0x00000000; + + EndSlot = HalpPciMaxSlots; + if (HalpSystemType == MOTOROLA_POWERSTACK) + EndSlot--; + + // + // Scan PCI slots for video BIOS ROMs, except 2 PCI "slots" on motherboard + // + for (Slot = 2; Slot < EndSlot; Slot++) { + + // + // Create a mapping to PCI configuration space + // + if( HalpPciConfigBase == NULL) { + + HalpPciConfigBase = KePhase0MapIo(PCI_CONFIG_PHYSICAL_BASE, HalpPciConfigSize); + + + if (HalpPciConfigBase == NULL) { + DbgPrint("\nCan't create mapping to PCI Configuration Space\n"); + return FALSE; + } + } + HalpVideoConfigBase = (PVOID) ((ULONG) HalpPciConfigBase + HalpPciConfigSlot[Slot]); + + // + // Read Vendor ID and check if slot is empty + // + VendorID = READ_REGISTER_USHORT(&((PCI_CONFIG)HalpVideoConfigBase)->VendorID); + if (VendorID == 0xFFFF) + continue; // Slot is empty; go to next slot + + // + // If Base Class does not indicate video, go to next slot + // + BaseClass = READ_REGISTER_UCHAR(&((PCI_CONFIG)HalpVideoConfigBase)->ClassCode[2]); + if (BaseClass != 0 && BaseClass != 3) + continue; + + + // + // Get size of ROM + // + WRITE_REGISTER_ULONG(&((PCI_CONFIG)HalpVideoConfigBase)->ROMbase, 0xFFFFFFFF); + ROM_size = READ_REGISTER_ULONG(&((PCI_CONFIG)HalpVideoConfigBase)->ROMbase); + + if ((ROM_size != 0xFFFFFFFF) && (ROM_size != 0)) { + + ROM_size = 0xD0000; // Map to end of option ROM space + + // + // Set Expansion ROM Base Address & enable ROM + // + PhysAddr.LowPart = 0x000C0000 | 1; + WRITE_REGISTER_ULONG(&((PCI_CONFIG)HalpVideoConfigBase)->ROMbase, PhysAddr.LowPart); + + + + // + // Enable Memory & I/O spaces in command register + // + Cmd = READ_REGISTER_USHORT(&((PCI_CONFIG)HalpVideoConfigBase)->Command); + WRITE_REGISTER_USHORT(&((PCI_CONFIG)HalpVideoConfigBase)->Command, Cmd | 3); + + // + // Delete the mapping to PCI config space + // + HalpPciConfigBase = HalpVideoConfigBase = NULL; + KePhase0DeleteIoMap( PCI_CONFIG_PHYSICAL_BASE, HalpPciConfigSize); + + // + // Create a mapping to the PCI memory space + // + HalpIoMemoryBase = KePhase0MapIo(PCI_MEMORY_BASE, ROM_size); + + if (HalpIoMemoryBase == NULL) { + DbgPrint("\nCan't create mapping to PCI memory space\n"); + return FALSE; + } + + // + // Look for PCI option video ROM signature + // + HalpRomBase = ROM_Ptr = (PUCHAR) HalpIoMemoryBase + 0xC0000; + if (*ROM_Ptr == 0x55 && *(ROM_Ptr+1) == 0xAA) { + + + // + // Copy ROM to RAM. PCI Spec says you can't execute from ROM. + // Sometimes option ROM and video RAM can't co-exist. + // + ROM_Length = *(ROM_Ptr+2) << 9; + if (ROM_Length <= BUFFER_SIZE) { + for (i=0; i<ROM_Length; i++) + ROM_Buffer[i] = *ROM_Ptr++; + HalpRomBase = (PUCHAR) ROM_Buffer; + } + + // + // Setup the PCI location for calling the BIOS init code. + // "Slot" needs to be translated into the device number + // suitable for CF8/CFC config accesses. In this case, + // if bit 11 set, dev = 11, etc. + // + HalpVideoBus = 0; + HalpVideoFunction = 0; + + i = HalpPciConfigSlot[Slot] >> 1; + HalpVideoDevice = 0; + + while (i) { + HalpVideoDevice++; + i >>= 1; + } + + HalpVideoDevice -= PCI_DEVICE_NUMBER_OFFSET; + + return TRUE; // Exit slot scan after finding 1st option ROM + } + + // + // Delete mapping to PCI memory space + // + HalpIoMemoryBase = NULL; + KePhase0DeleteIoMap(PCI_MEMORY_BASE, HalpPciConfigSize); + + // + // Restore PCI command register + // + HalpPciConfigBase = KePhase0MapIo(PCI_CONFIG_PHYSICAL_BASE, HalpPciConfigSize); + + if (HalpPciConfigBase == NULL) { + DbgPrint("\nCan't create mapping to PCI Configuration Space\n"); + return FALSE; + } + HalpVideoConfigBase = (PVOID) ((ULONG) HalpPciConfigBase + HalpPciConfigSlot[Slot]); + WRITE_REGISTER_USHORT(&((PCI_CONFIG)HalpVideoConfigBase)->Command, Cmd); + + + } // end of if clause + } // end of for loop + + + // + // Delete mapping to PCI config space + // + if (HalpPciConfigBase) { + HalpPciConfigBase = NULL; + KePhase0DeleteIoMap(PCI_CONFIG_PHYSICAL_BASE, HalpPciConfigSize); + } + + + // + // Create a mapping to ISA memory space, unless one already exists + // + if (HalpIoMemoryBase == NULL) { + HalpIoMemoryBase = KePhase0MapIo(PCI_MEMORY_BASE, ROM_size); + } + + + if (HalpIoMemoryBase == NULL) { + return FALSE; + } else { + // + // Look for ISA option video ROM signature + // + ROM_Ptr = (PUCHAR) HalpIoMemoryBase + 0xC0000; + HalpRomBase = ROM_Ptr; + if (*ROM_Ptr == 0x55 && *(ROM_Ptr+1) == 0xAA) { + // + // Copy ROM to RAM. PCI Spec says you can't execute from ROM. + // ROM and video RAM sometimes can't co-exist. + // + ROM_Length = *(ROM_Ptr+2) << 9; + if (ROM_Length <= BUFFER_SIZE) { + for (i=0; i<ROM_Length; i++) + ROM_Buffer[i] = *ROM_Ptr++; + HalpRomBase = (PUCHAR) ROM_Buffer; + } + return TRUE; + } + + // + // No video option ROM was found. Delete mapping to PCI memory space. + // + KePhase0DeleteIoMap(PCI_MEMORY_BASE, ROM_size); + + + return FALSE; + } +} + + + + +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. + +--*/ + +{ + +#if defined(USE_BIOS_EMULATOR) + + XM86_CONTEXT Context; + + // + // If the x86 BIOS Emulator has not been initialized, then return FALSE. + // + + if (HalpX86BiosInitialized == FALSE) { + return FALSE; + } + + // + // If the Video Adapter initialization failed and an Int10 command is + // specified, then return FALSE. + // + + if ((BiosCommand == 0x10) && (HalpEnableInt10Calls == FALSE)) { + return FALSE; + } + + // + // Copy the x86 bios context and emulate the specified command. + // + + Context.Eax = *Eax; + Context.Ebx = *Ebx; + Context.Ecx = *Ecx; + Context.Edx = *Edx; + Context.Esi = *Esi; + Context.Edi = *Edi; + Context.Ebp = *Ebp; + if (x86BiosExecuteInterrupt((UCHAR)BiosCommand, + &Context, + HalpIoControlBase, + HalpIoMemoryBase) != XM_SUCCESS) { + return FALSE; + } + + // + // Copy the x86 bios context and return TRUE. + // + + *Eax = Context.Eax; + *Ebx = Context.Ebx; + *Ecx = Context.Ecx; + *Edx = Context.Edx; + *Esi = Context.Esi; + *Edi = Context.Edi; + *Ebp = Context.Ebp; + return TRUE; + +#else + + return FALSE; + +#endif + +} + +BOOLEAN +HalpInitializeX86DisplayAdapter( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ) + +/*++ + +Routine Description: + + This function initializes a display adapter using the x86 bios emulator. + +Arguments: + + LoaderBlock for access to the number of PCI buses + +Return Value: + + None. + +--*/ + +{ + +#if defined(USE_BIOS_EMULATOR) + PCONFIGURATION_COMPONENT_DATA ConfigurationEntry; + PPCI_REGISTRY_INFO PCIRegInfo; + ULONG MatchKey; + PCM_PARTIAL_RESOURCE_LIST Descriptor; + PCM_PARTIAL_RESOURCE_DESCRIPTOR Partial; + XM86_CONTEXT State; + + // + // If EISA I/O Ports or EISA memory could not be mapped, then don't + // attempt to initialize the display adapter. + // + + if (!HalpInitX86Emulator()) + return FALSE; + + if (HalpIoControlBase == NULL || HalpIoMemoryBase == NULL) { + return FALSE; + } + + // + // Get the number of PCI buses for the PCI BIOS functions + // + + // + // Find the PCI info in the config data. + // + HalpLastPciBus = 0; + MatchKey = 0; + while ((ConfigurationEntry=KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot, + AdapterClass, MultiFunctionAdapter, &MatchKey)) != NULL) { + + if (!strcmp(ConfigurationEntry->ComponentEntry.Identifier,"PCI")) { + + Descriptor = (PCM_PARTIAL_RESOURCE_LIST)ConfigurationEntry->ConfigurationData; + + PCIRegInfo = (PPCI_REGISTRY_INFO)&Descriptor->PartialDescriptors[1]; + + HalpLastPciBus = PCIRegInfo->NoBuses - 1; + + break; + } + + MatchKey++; + } + + + // + // Initialize the x86 bios emulator. + // + + x86BiosInitializeBios(HalpIoControlBase, HalpIoMemoryBase); + HalpX86BiosInitialized = TRUE; + + // + // Attempt to initialize the display adapter by executing its ROM bios + // code. The standard ROM bios code address for PC video adapters is + // 0xC000:0000 on the ISA bus. + // + + State.Eax = (HalpVideoBus << 8) | + (HalpVideoDevice << 3) | + HalpVideoFunction; + + State.Ecx = 0; + State.Edx = 0; + State.Ebx = 0; + State.Ebp = 0; + State.Esi = 0; + State.Edi = 0; + + if (x86BiosInitializeAdapter(0xc0000, &State, HalpIoControlBase, HalpIoMemoryBase) != XM_SUCCESS) { + HalpEnableInt10Calls = FALSE; + return FALSE; + } + HalpEnableInt10Calls = TRUE; + +#endif + + return TRUE; +} + +VOID +HalpResetX86DisplayAdapter( + VOID + ) + +/*++ + +Routine Description: + + This function resets a display adapter using the x86 bios emulator. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + +#if defined(USE_BIOS_EMULATOR) + + XM86_CONTEXT Context; + + // + // Initialize the x86 bios context and make the INT 10 call to initialize + // the display adapter to 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); + +#endif + + return; +} + + +// +// This code came from ..\..\x86new\x86bios.c +// +#define LOW_MEMORY_SIZE 0x800 +extern UCHAR x86BiosLowMemory[LOW_MEMORY_SIZE + 3]; +extern ULONG x86BiosScratchMemory; +extern ULONG x86BiosIoMemory; +extern ULONG x86BiosIoSpace; + + +PVOID +x86BiosTranslateAddress ( + IN USHORT Segment, + IN USHORT Offset + ) + +/*++ + +Routine Description: + + This translates a segment/offset address into a memory address. + +Arguments: + + Segment - Supplies the segment register value. + + Offset - Supplies the offset within segment. + +Return Value: + + The memory address of the translated segment/offset pair is + returned as the function value. + +--*/ + +{ + + ULONG Value; + + // + // Compute the logical memory address and case on high hex digit of + // the resultant address. + // + + Value = Offset + (Segment << 4); + Offset = (USHORT)(Value & 0xffff); + Value &= 0xf0000; + switch ((Value >> 16) & 0xf) { + + // + // Interrupt vector/stack space. + // + + case 0x0: + if (Offset > LOW_MEMORY_SIZE) { + x86BiosScratchMemory = 0; + return (PVOID)&x86BiosScratchMemory; + + } else { + return (PVOID)(&x86BiosLowMemory[0] + Offset); + } + + // + // The memory range from 0x10000 to 0x9ffff reads as zero + // and writes are ignored. + // + + case 0x1: + case 0x2: + case 0x3: + case 0x4: + case 0x5: + case 0x6: + case 0x7: + case 0x8: + case 0x9: + x86BiosScratchMemory = 0; + return (PVOID)&x86BiosScratchMemory; + + // + // The memory range from 0xa0000 to 0xdffff maps to I/O memory. + // + + case 0xa: + case 0xb: + return (PVOID)(x86BiosIoMemory + Offset + Value); + + case 0xc: + case 0xd: + return (PVOID)(HalpRomBase + Offset); + + // + // The memory range from 0x10000 to 0x9ffff reads as zero + // and writes are ignored. + // + + case 0xe: + case 0xf: + x86BiosScratchMemory = 0; + return (PVOID)&x86BiosScratchMemory; + } + + // NOT REACHED - NOT EXECUTED - Prevents Compiler Warning. + return (PVOID)NULL; +} + + +VOID HalpCopyROMs(VOID) +{ +ULONG i; +PUCHAR ROM_Shadow; + + if (ROM_Buffer[0] == 0x55 && ROM_Buffer[1] == 0xAA) { + HalpRomBase = ROM_Shadow = ExAllocatePool(NonPagedPool, ROM_Length); + for (i=0; i<ROM_Length; i++) { + *ROM_Shadow++ = ROM_Buffer[i]; + } + } +} + + +/****Include File x86new\x86bios.c Here - except the routine x86BiosTranslateAddress. ****/ + +/*++ + +Copyright (c) 1994 Microsoft Corporation + +Module Name: + + x86bios.c + +Abstract: + + This module implements supplies the HAL interface to the 386/486 + real mode emulator for the purpose of emulating BIOS calls.. + +Author: + + David N. Cutler (davec) 13-Nov-1994 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "nthal.h" +#include "hal.h" +#include "xm86.h" +#include "x86new.h" + +// +// Define the size of low memory. +// + +#define LOW_MEMORY_SIZE 0x800 +// +// Define storage for low emulated memory. +// + +UCHAR x86BiosLowMemory[LOW_MEMORY_SIZE + 3]; +ULONG x86BiosScratchMemory; + +// +// Define storage to capture the base address of I/O space and the +// base address of I/O memory space. +// + +ULONG x86BiosIoMemory; +ULONG x86BiosIoSpace; + +// +// Define BIOS initialized state. +// + +BOOLEAN x86BiosInitialized = FALSE; + +// +// Hardware Configuration Mechanism #1 emulation. +// +// The eagle does not distinguish between CF8 and CFC on reads. +// At least one BIOS we know of writes/reads CF8 to see if HW +// mechanism 1 is implemented. +// +ULONG x86CF8Shadow; + +// +// Hardware Configuration Mechanism #2 emulation. +// +static struct { + UCHAR CSE; + UCHAR Forward; +} x86ConfigMechanism2 = { 0, 0}; + +ULONG +x86BiosReadIoSpace ( + IN XM_OPERATION_DATATYPE DataType, + IN USHORT PortNumber + ) + +/*++ + +Routine Description: + + This function reads from emulated I/O space. + +Arguments: + + DataType - Supplies the datatype for the read operation. + + PortNumber - Supplies the port number in I/O space to read from. + +Return Value: + + The value read from I/O space is returned as the function value. + + N.B. If an aligned operation is specified, then the individual + bytes are read from the specified port one at a time and + assembled into the specified datatype. + +--*/ + +{ + + ULONG Result; + + union { + PUCHAR Byte; + PUSHORT Word; + PULONG Long; + } u; + + // + // Convert mechanism #2 config accesses to mechanism #1. + // + if (((PortNumber & 0xF000) == 0xC000) && + ((x86ConfigMechanism2.CSE & 0xF0) != 0)) { + + WRITE_REGISTER_ULONG(x86BiosIoSpace + 0xCF8, + (1 << 31) | // Enable + (x86ConfigMechanism2.Forward << 16) | // Bus + ((((PortNumber & 0x0F00) >> 8) + 11) << 11) | // Dev + (((x86ConfigMechanism2.CSE & 0x0E) >> 1) << 8) | // Function + (PortNumber & 0x00FC) // Register + ); + + PortNumber = 0xCFC + (PortNumber & 3); // convert to config data port + // and let code below do the rest + } + + // + // Compute port address and read port. + // + + u.Long = (PULONG)(x86BiosIoSpace + PortNumber); + if (DataType == BYTE_DATA) { + // + // Emulate config mechanism #2 + // + if (PortNumber == 0xCF8) { + Result = x86ConfigMechanism2.CSE; + } else if (PortNumber == 0xCFA) { + Result = x86ConfigMechanism2.Forward; + } else { + Result = READ_REGISTER_UCHAR(u.Byte); + } + + } else if (DataType == LONG_DATA) { + if (((ULONG)u.Long & 0x3) != 0) { + Result = (READ_REGISTER_UCHAR(u.Byte + 0)) | + (READ_REGISTER_UCHAR(u.Byte + 1) << 8) | + (READ_REGISTER_UCHAR(u.Byte + 2) << 16) | + (READ_REGISTER_UCHAR(u.Byte + 3) << 24); + + } else { + // + // Watch out for reads from CF8, the eagle will generate a config + // cycle rather than returning the contents of the CONFIG_ADDR reg. + // + if (PortNumber == 0xCF8) { + + Result = x86CF8Shadow; + + } else { + + Result = READ_REGISTER_ULONG(u.Long); + } + } + + } else { + if (((ULONG)u.Word & 0x1) != 0) { + Result = (READ_REGISTER_UCHAR(u.Byte + 0)) | + (READ_REGISTER_UCHAR(u.Byte + 1) << 8); + + } else { + Result = READ_REGISTER_USHORT(u.Word); + } + } + + return Result; +} + +VOID +x86BiosWriteIoSpace ( + IN XM_OPERATION_DATATYPE DataType, + IN USHORT PortNumber, + IN ULONG Value + ) + +/*++ + +Routine Description: + + This function write to emulated I/O space. + + N.B. If an aligned operation is specified, then the individual + bytes are written to the specified port one at a time. + +Arguments: + + DataType - Supplies the datatype for the write operation. + + PortNumber - Supplies the port number in I/O space to write to. + + Value - Supplies the value to write. + +Return Value: + + None. + +--*/ + +{ + + union { + PUCHAR Byte; + PUSHORT Word; + PULONG Long; + } u; + + // + // Convert mechanism #2 config accesses to mechanism #1. + // + if (((PortNumber & 0xF000) == 0xC000) && + ((x86ConfigMechanism2.CSE & 0xF0) != 0)) { + + WRITE_REGISTER_ULONG(x86BiosIoSpace + 0xCF8, + (1 << 31) | // Enable + (x86ConfigMechanism2.Forward << 16) | // Bus + ((((PortNumber & 0x0F00) >> 8) + 11) << 11) | // Dev + (((x86ConfigMechanism2.CSE & 0x0E) >> 1) << 8) | // Function + (PortNumber & 0x00FC) // Register + ); + + PortNumber = 0xCFC + (PortNumber & 3); // convert to config data port + // and let code below do the rest + } + + // + // Compute port address and read port. + // + + u.Long = (PULONG)(x86BiosIoSpace + PortNumber); + if (DataType == BYTE_DATA) { + // + // Emulate config mechanism #2 + // + if (PortNumber == 0xCF8) { + x86ConfigMechanism2.CSE = (UCHAR)Value; + } else if (PortNumber == 0xCFA) { + x86ConfigMechanism2.Forward = (UCHAR)Value; + } else { + WRITE_REGISTER_UCHAR(u.Byte, (UCHAR)Value); + } + + } else if (DataType == LONG_DATA) { + if (((ULONG)u.Long & 0x3) != 0) { + WRITE_REGISTER_UCHAR(u.Byte + 0, (UCHAR)(Value)); + WRITE_REGISTER_UCHAR(u.Byte + 1, (UCHAR)(Value >> 8)); + WRITE_REGISTER_UCHAR(u.Byte + 2, (UCHAR)(Value >> 16)); + WRITE_REGISTER_UCHAR(u.Byte + 3, (UCHAR)(Value >> 24)); + + } else { + WRITE_REGISTER_ULONG(u.Long, Value); + + // + // Shadow writes to CF8. + // + if (PortNumber == 0xCF8) { + x86CF8Shadow = Value; + } + } + + } else { + if (((ULONG)u.Word & 0x1) != 0) { + WRITE_REGISTER_UCHAR(u.Byte + 0, (UCHAR)(Value)); + WRITE_REGISTER_UCHAR(u.Byte + 1, (UCHAR)(Value >> 8)); + + } else { + WRITE_REGISTER_USHORT(u.Word, (USHORT)Value); + } + } + + return; +} + +VOID +x86BiosInitializeBios ( + IN PVOID BiosIoSpace, + IN PVOID BiosIoMemory + ) + +/*++ + +Routine Description: + + This function initializes x86 BIOS emulation. + +Arguments: + + BiosIoSpace - Supplies the base address of the I/O space to be used + for BIOS emulation. + + BiosIoMemory - Supplies the base address of the I/O memory to be + used for BIOS emulation. + +Return Value: + + None. + +--*/ + +{ + + // + // Zero low memory. + // + + memset(&x86BiosLowMemory, 0, LOW_MEMORY_SIZE); + + // + // Save base address of I/O memory and I/O space. + // + + x86BiosIoSpace = (ULONG)BiosIoSpace; + x86BiosIoMemory = (ULONG)BiosIoMemory; + + // + // Initialize the emulator and the BIOS. + // + + XmInitializeEmulator(0, + LOW_MEMORY_SIZE, + x86BiosReadIoSpace, + x86BiosWriteIoSpace, + x86BiosTranslateAddress); + + x86BiosInitialized = TRUE; + return; +} + +XM_STATUS +x86BiosExecuteInterrupt ( + IN UCHAR Number, + IN OUT PXM86_CONTEXT Context, + IN PVOID BiosIoSpace OPTIONAL, + IN PVOID BiosIoMemory OPTIONAL + ) + +/*++ + +Routine Description: + + This function executes an interrupt by calling the x86 emulator. + +Arguments: + + Number - Supplies the number of the interrupt that is to be emulated. + + Context - Supplies a pointer to an x86 context structure. + +Return Value: + + The emulation completion status. + +--*/ + +{ + + XM_STATUS Status; + + // + // If a new base address is specified, then set the appropriate base. + // + + if (BiosIoSpace != NULL) { + x86BiosIoSpace = (ULONG)BiosIoSpace; + } + + if (BiosIoMemory != NULL) { + x86BiosIoMemory = (ULONG)BiosIoMemory; + } + + // + // Execute the specified interrupt. + // + + Status = XmEmulateInterrupt(Number, Context); + if (Status != XM_SUCCESS) { + DbgPrint("HAL: Interrupt emulation failed, status %lx\n", Status); + } + + return Status; +} + +XM_STATUS +x86BiosInitializeAdapter ( + IN ULONG Adapter, + IN OUT PXM86_CONTEXT Context OPTIONAL, + IN PVOID BiosIoSpace OPTIONAL, + IN PVOID BiosIoMemory OPTIONAL + ) + +/*++ + +Routine Description: + + This function initializes the adapter whose BIOS starts at the + specified 20-bit address. + +Arguments: + + Adpater - Supplies the 20-bit address of the BIOS for the adapter + to be initialized. + +Return Value: + + The emulation completion status. + +--*/ + +{ + + PUCHAR Byte; + XM86_CONTEXT State; + USHORT Offset; + USHORT Segment; + XM_STATUS Status; + + // + // If BIOS emulation has not been initialized, then return an error. + // + + if (x86BiosInitialized == FALSE) { + return XM_EMULATOR_NOT_INITIALIZED; + } + + // + // If an emulator context is not specified, then use a default + // context. + // + + if (ARGUMENT_PRESENT(Context) == FALSE) { + State.Eax = 0; + State.Ecx = 0; + State.Edx = 0; + State.Ebx = 0; + State.Ebp = 0; + State.Esi = 0; + State.Edi = 0; + Context = &State; + } + + // + // If a new base address is specified, then set the appropriate base. + // + + if (BiosIoSpace != NULL) { + x86BiosIoSpace = (ULONG)BiosIoSpace; + } + + if (BiosIoMemory != NULL) { + x86BiosIoMemory = (ULONG)BiosIoMemory; + } + + // + // If the specified adpater is not BIOS code, then return an error. + // + + Segment = (USHORT)((Adapter >> 4) & 0xf000); + Offset = (USHORT)(Adapter & 0xffff); + Byte = (PUCHAR)x86BiosTranslateAddress(Segment, Offset); + if ((*Byte++ != 0x55) || (*Byte != 0xaa)) { + return XM_ILLEGAL_CODE_SEGMENT; + } + + // + // Call the BIOS code to initialize the specified adapter. + // + + Adapter += 3; + Segment = (USHORT)((Adapter >> 4) & 0xf000); + Offset = (USHORT)(Adapter & 0xffff); + Status = XmEmulateFarCall(Segment, Offset, Context); + if (Status != XM_SUCCESS) { + DbgPrint("HAL: Adapter initialization falied, status %lx\n", Status); + } + + return Status; +} + diff --git a/private/ntos/nthals/haleagle/sources b/private/ntos/nthals/haleagle/sources new file mode 100644 index 000000000..858f3bce6 --- /dev/null +++ b/private/ntos/nthals/haleagle/sources @@ -0,0 +1,97 @@ +!IF 0 + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + Motorola Eagle based systems. + + + +Author: + + Bill Jones - 12/15/94 + +!ENDIF + +MAJORCOMP=ntos +MINORCOMP=hal + +TARGETNAME=haleagle +TARGETPATH=$(BASEDIR)\public\sdk\lib +TARGETLIBS=..\x86new\obj\*\x86new.lib \ + $(BASEDIR)\public\sdk\lib\*\libc.lib + +!IF $(PPC) + +TARGETTYPE=HAL + +!ELSE + +TARGETTYPE=DRIVER + +!ENDIF + +C_DEFINES=-D_HALNVR_ + +INCLUDES=..\x86new;..\..\inc; + +SOURCES= + +PPC_SOURCES=hal.rc \ + drivesup.c \ + bushnd.c \ + rangesup.c \ + ppc\fwnvr.c \ + ppc\mk48time.c \ + ppc\pxbeep.c \ + ppc\pxbusdat.c \ + ppc\pxcache.s \ + ppc\pxcalstl.c \ + ppc\pxclksup.s \ + ppc\pxclock.c \ + ppc\pxdat.c \ + ppc\pxdisp.c \ + ppc\pxds1385.c \ + ppc\pxenviro.c \ + ppc\pxflshbf.s \ + ppc\pxflshio.c \ + ppc\pxhwsup.c \ + ppc\pxidle.c \ + ppc\pxinfo.c \ + ppc\pxinithl.c \ + ppc\pxintsup.s \ + ppc\pxirql.c \ + ppc\pxisabus.c \ + ppc\pxl2.s \ + ppc\pxmapio.c \ + ppc\pxmemctl.c \ + ppc\pxmisc.s \ + ppc\pxpcibrd.c \ + ppc\pxpcibus.c \ + ppc\pxpciint.c \ + ppc\pxpcisup.c \ + ppc\pxport.c \ + ppc\pxpower.s \ + ppc\pxproc.c \ + ppc\pxprof.c \ + ppc\pxreset.s \ + ppc\pxreturn.c \ + ppc\pxsiosup.c \ + ppc\pxstall.s \ + ppc\pxsysbus.c \ + ppc\pxsysint.c \ + ppc\pxsystyp.c \ + ppc\pxtime.c \ + ppc\pxusage.c \ + ppc\x86bios.c \ + ppc\ctrlops.c \ + ppc\sysbios.c \ + ppc\pcibios.c + +DLLDEF=obj\*\hal.def + |