summaryrefslogtreecommitdiffstats
path: root/private/ntos/nthals/halx86/i386
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/nthals/halx86/i386
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/nthals/halx86/i386')
-rw-r--r--private/ntos/nthals/halx86/i386/halnls.h29
-rw-r--r--private/ntos/nthals/halx86/i386/halp.h428
-rw-r--r--private/ntos/nthals/halx86/i386/ix8259.inc199
-rw-r--r--private/ntos/nthals/halx86/i386/ixbeep.asm181
-rw-r--r--private/ntos/nthals/halx86/i386/ixbusdat.c373
-rw-r--r--private/ntos/nthals/halx86/i386/ixclock.asm760
-rw-r--r--private/ntos/nthals/halx86/i386/ixcmos.asm1135
-rw-r--r--private/ntos/nthals/halx86/i386/ixcmos.inc66
-rw-r--r--private/ntos/nthals/halx86/i386/ixdat.c159
-rw-r--r--private/ntos/nthals/halx86/i386/ixenvirv.c183
-rw-r--r--private/ntos/nthals/halx86/i386/ixfirm.c79
-rw-r--r--private/ntos/nthals/halx86/i386/ixhwsup.c758
-rw-r--r--private/ntos/nthals/halx86/i386/ixidle.asm88
-rw-r--r--private/ntos/nthals/halx86/i386/ixinfo.c285
-rw-r--r--private/ntos/nthals/halx86/i386/ixipi.asm188
-rw-r--r--private/ntos/nthals/halx86/i386/ixirql.asm1297
-rw-r--r--private/ntos/nthals/halx86/i386/ixisa.h110
-rw-r--r--private/ntos/nthals/halx86/i386/ixisabus.c640
-rw-r--r--private/ntos/nthals/halx86/i386/ixisasup.c1980
-rw-r--r--private/ntos/nthals/halx86/i386/ixkdcom.c684
-rw-r--r--private/ntos/nthals/halx86/i386/ixkdcom.h165
-rw-r--r--private/ntos/nthals/halx86/i386/ixlock.asm475
-rw-r--r--private/ntos/nthals/halx86/i386/ixmca.c868
-rw-r--r--private/ntos/nthals/halx86/i386/ixmcaa.asm420
-rw-r--r--private/ntos/nthals/halx86/i386/ixnmi.c137
-rw-r--r--private/ntos/nthals/halx86/i386/ixpcibrd.c1029
-rw-r--r--private/ntos/nthals/halx86/i386/ixpcibus.c2520
-rw-r--r--private/ntos/nthals/halx86/i386/ixpciint.c458
-rw-r--r--private/ntos/nthals/halx86/i386/ixphwsup.c535
-rw-r--r--private/ntos/nthals/halx86/i386/ixproc.c160
-rw-r--r--private/ntos/nthals/halx86/i386/ixprofil.asm437
-rw-r--r--private/ntos/nthals/halx86/i386/ixreboot.c143
-rw-r--r--private/ntos/nthals/halx86/i386/ixstall.asm480
-rw-r--r--private/ntos/nthals/halx86/i386/ixswint.asm327
-rw-r--r--private/ntos/nthals/halx86/i386/ixsysbus.c188
-rw-r--r--private/ntos/nthals/halx86/i386/ixsysint.asm582
-rw-r--r--private/ntos/nthals/halx86/i386/ixthunk.c82
-rw-r--r--private/ntos/nthals/halx86/i386/ixusage.c535
-rw-r--r--private/ntos/nthals/halx86/i386/ncrdetct.c253
-rw-r--r--private/ntos/nthals/halx86/i386/pcip.h186
-rw-r--r--private/ntos/nthals/halx86/i386/xxbiosa.asm712
-rw-r--r--private/ntos/nthals/halx86/i386/xxbiosc.c299
-rw-r--r--private/ntos/nthals/halx86/i386/xxdisp.c476
-rw-r--r--private/ntos/nthals/halx86/i386/xxflshbf.c52
-rw-r--r--private/ntos/nthals/halx86/i386/xxhal.c462
-rw-r--r--private/ntos/nthals/halx86/i386/xxioacc.asm386
-rw-r--r--private/ntos/nthals/halx86/i386/xxkdsup.c404
-rw-r--r--private/ntos/nthals/halx86/i386/xxmemory.c368
-rw-r--r--private/ntos/nthals/halx86/i386/xxstubs.c131
-rw-r--r--private/ntos/nthals/halx86/i386/xxtime.c91
50 files changed, 22983 insertions, 0 deletions
diff --git a/private/ntos/nthals/halx86/i386/halnls.h b/private/ntos/nthals/halx86/i386/halnls.h
new file mode 100644
index 000000000..56dc7d557
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/halnls.h
@@ -0,0 +1,29 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ halnls.h
+
+Abstract:
+
+ Strings which are used in the HAL
+
+ English
+
+--*/
+
+#define MSG_HARDWARE_ERROR1 "\n*** Hardware Malfunction\n\n"
+#define MSG_HARDWARE_ERROR2 "Call your hardware vendor for support\n\n"
+#define MSG_HALT "\n*** The system has halted ***\n"
+#define MSG_NMI_PARITY "NMI: Parity Check / Memory Parity Error\n"
+#define MSG_NMI_CHANNEL_CHECK "NMI: Channel Check / IOCHK\n"
+#define MSG_NMI_FAIL_SAFE "NMI: Fail-safe timer\n"
+#define MSG_NMI_BUS_TIMEOUT "NMI: Bus Timeout\n"
+#define MSG_NMI_SOFTWARE_NMI "NMI: Software NMI generated\n"
+#define MSG_NMI_EISA_IOCHKERR "NMI: Eisa IOCHKERR board %\n"
+
+#define MSG_DEBUG_ENABLE "Kernel Debugger Using: COM%x (Port 0x%x, Baud Rate %d)\n"
+#define MSG_DEBUG_9600 "Switching debugger to 9600 baud\n"
+#define MSG_MCE_PENDING "Machine Check Exception pending, MCE exceptions not enabled\n"
diff --git a/private/ntos/nthals/halx86/i386/halp.h b/private/ntos/nthals/halx86/i386/halp.h
new file mode 100644
index 000000000..fb3fed047
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/halp.h
@@ -0,0 +1,428 @@
+/*++ BUILD Version: 0001 // Increment this if a change has global effects
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ halp.h
+
+Abstract:
+
+ This header file defines the private Hardware Architecture Layer (HAL)
+ interfaces, defines and structures.
+
+Author:
+
+ John Vert (jvert) 11-Feb-92
+
+
+Revision History:
+
+--*/
+
+#ifndef _HALP_
+#define _HALP_
+#include "nthal.h"
+#include "hal.h"
+#include "halnls.h"
+
+#ifndef _HALI_
+#include "..\inc\hali.h"
+#endif
+
+#ifdef RtlMoveMemory
+#undef RtlMoveMemory
+#undef RtlCopyMemory
+#undef RtlFillMemory
+#undef RtlZeroMemory
+
+#define RtlCopyMemory(Destination,Source,Length) RtlMoveMemory((Destination),(Source),(Length))
+VOID
+RtlMoveMemory (
+ PVOID Destination,
+ CONST VOID *Source,
+ ULONG Length
+ );
+
+VOID
+RtlFillMemory (
+ PVOID Destination,
+ ULONG Length,
+ UCHAR Fill
+ );
+
+VOID
+RtlZeroMemory (
+ PVOID Destination,
+ ULONG Length
+ );
+
+#endif
+
+#if MCA
+
+#include "ixmca.h"
+
+#else
+
+#include "ixisa.h"
+
+#endif
+
+#include "ix8259.inc"
+
+//
+// Define map register translation entry structure.
+//
+
+typedef struct _TRANSLATION_ENTRY {
+ PVOID VirtualAddress;
+ ULONG PhysicalAddress;
+ ULONG Index;
+} TRANSLATION_ENTRY, *PTRANSLATION_ENTRY;
+
+//
+// Some devices require a phyicially contiguous data buffers for DMA transfers.
+// Map registers are used give the appearance that all data buffers are
+// contiguous. In order to pool all of the map registers a master
+// adapter object is used. This object is allocated and saved internal to this
+// file. It contains a bit map for allocation of the registers and a queue
+// for requests which are waiting for more map registers. This object is
+// allocated during the first request to allocate an adapter which requires
+// map registers.
+//
+// In this system, the map registers are translation entries which point to
+// map buffers. Map buffers are physically contiguous and have physical memory
+// addresses less than 0x01000000. All of the map registers are allocated
+// initialially; however, the map buffers are allocated base in the number of
+// adapters which are allocated.
+//
+// If the master adapter is NULL in the adapter object then device does not
+// require any map registers.
+//
+
+extern PADAPTER_OBJECT MasterAdapterObject;
+
+extern POBJECT_TYPE *IoAdapterObjectType;
+
+extern BOOLEAN LessThan16Mb;
+
+extern BOOLEAN HalpEisaDma;
+
+//
+// Map buffer prameters. These are initialized in HalInitSystem
+//
+
+extern PHYSICAL_ADDRESS HalpMapBufferPhysicalAddress;
+extern ULONG HalpMapBufferSize;
+
+extern ULONG HalpBusType;
+extern ULONG HalpCpuType;
+extern UCHAR HalpSerialLen;
+extern UCHAR HalpSerialNumber[];
+
+//
+// The following macros are taken from mm\i386\mi386.h. We need them here
+// so the HAL can map its own memory before memory-management has been
+// initialized, or during a BugCheck.
+//
+
+#define PTE_BASE ((ULONG)0xC0000000)
+#define PDE_BASE ((ULONG)0xC0300000)
+
+//
+// MiGetPdeAddress returns the address of the PDE which maps the
+// given virtual address.
+//
+
+#define MiGetPdeAddress(va) ((PHARDWARE_PTE)(((((ULONG)(va)) >> 22) << 2) + PDE_BASE))
+
+//
+// MiGetPteAddress returns the address of the PTE which maps the
+// given virtual address.
+//
+
+#define MiGetPteAddress(va) ((PHARDWARE_PTE)(((((ULONG)(va)) >> 12) << 2) + PTE_BASE))
+
+//
+// Resource usage information
+//
+
+#pragma pack(1)
+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;
+ ULONG Length;
+ } Element[];
+} ADDRESS_USAGE;
+#pragma pack()
+
+#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);
+
+//
+// Temp definitions to thunk into supporting new bus extension format
+//
+
+VOID
+HalpRegisterInternalBusHandlers (
+ VOID
+ );
+
+PBUS_HANDLER
+HalpAllocateBusHandler (
+ IN INTERFACE_TYPE InterfaceType,
+ IN BUS_DATA_TYPE BusDataType,
+ IN ULONG BusNumber,
+ IN INTERFACE_TYPE ParentBusDataType,
+ IN ULONG ParentBusNumber,
+ IN ULONG BusSpecificData
+ );
+
+#define HalpHandlerForBus HaliHandlerForBus
+#define HalpSetBusHandlerParent(c,p) (c)->ParentHandler = p;
+
+//
+// Define function prototypes.
+//
+
+VOID
+HalInitSystemPhase2(
+ VOID
+ );
+
+KIRQL
+HaliRaiseIrqlToDpcLevel (
+ VOID
+ );
+
+BOOLEAN
+HalpGrowMapBuffers(
+ PADAPTER_OBJECT AdapterObject,
+ ULONG Amount
+ );
+
+PADAPTER_OBJECT
+HalpAllocateAdapter(
+ IN ULONG MapRegistersPerChannel,
+ IN PVOID AdapterBaseVa,
+ IN PVOID MapRegisterBase
+ );
+
+VOID
+HalpClockInterrupt(
+ VOID
+ );
+
+VOID
+HalpDisableAllInterrupts (
+ VOID
+ );
+
+VOID
+HalpProfileInterrupt(
+ VOID
+ );
+
+VOID
+HalpInitializeClock(
+ VOID
+ );
+
+VOID
+HalpInitializeDisplay(
+ VOID
+ );
+
+VOID
+HalpInitializeStallExecution(
+ IN CCHAR ProcessorNumber
+ );
+
+VOID
+HalpInitializePICs(
+ VOID
+ );
+
+VOID
+HalpIrq13Handler (
+ VOID
+ );
+
+VOID
+HalpFlushTLB (
+ VOID
+ );
+
+VOID
+HalpSerialize (
+ VOID
+ );
+
+PVOID
+HalpMapPhysicalMemory(
+ IN PVOID PhysicalAddress,
+ IN ULONG NumberPages
+ );
+
+PVOID
+HalpMapPhysicalMemoryWriteThrough(
+ IN PVOID PhysicalAddress,
+ IN ULONG NumberPages
+ );
+
+ULONG
+HalpAllocPhysicalMemory(
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock,
+ IN ULONG MaxPhysicalAddress,
+ IN ULONG NoPages,
+ IN BOOLEAN bAlignOn64k
+ );
+
+VOID
+HalpBiosDisplayReset(
+ IN VOID
+ );
+
+HAL_DISPLAY_BIOS_INFORMATION
+HalpGetDisplayBiosInformation (
+ VOID
+ );
+
+VOID
+HalpDisplayDebugStatus(
+ IN PUCHAR Status,
+ IN ULONG Length
+ );
+
+VOID
+HalpInitializeCmos (
+ VOID
+ );
+
+VOID
+HalpReadCmosTime (
+ PTIME_FIELDS TimeFields
+ );
+
+VOID
+HalpWriteCmosTime (
+ PTIME_FIELDS TimeFields
+ );
+
+VOID
+HalpAcquireCmosSpinLock (
+ VOID
+ );
+
+VOID
+HalpReleaseCmosSpinLock (
+ VOID
+ );
+
+VOID
+HalpResetAllProcessors (
+ VOID
+ );
+
+VOID
+HalpCpuID (
+ ULONG InEax,
+ PULONG OutEax,
+ PULONG OutEbx,
+ PULONG OutEcx,
+ PULONG OutEdx
+ );
+
+ULONGLONG
+FASTCALL
+RDMSR (
+ IN ULONG MsrAddress
+ );
+
+VOID
+WRMSR (
+ IN ULONG MsrAddress,
+ IN ULONGLONG MsrValue
+ );
+
+VOID
+HalpEnableInterruptHandler (
+ IN UCHAR ReportFlags,
+ IN ULONG BusInterruptVector,
+ IN ULONG SystemInterruptVector,
+ IN KIRQL SystemIrql,
+ IN VOID (*HalInterruptServiceRoutine)(VOID),
+ IN KINTERRUPT_MODE InterruptMode
+ );
+
+VOID
+HalpRegisterVector (
+ IN UCHAR ReportFlags,
+ IN ULONG BusInterruptVector,
+ IN ULONG SystemInterruptVector,
+ IN KIRQL SystemIrql
+ );
+
+VOID
+HalpReportResourceUsage (
+ IN PUNICODE_STRING HalName,
+ IN INTERFACE_TYPE DeviceInterfaceToUse
+ );
+
+
+//
+// Defines for HalpFeatureBits
+//
+
+#define HAL_PERF_EVENTS 0x00000001
+#define HAL_NO_SPECULATION 0x00000002
+#define HAL_MCA_PRESENT 0x00000004 // Intel MCA Available
+#define HAL_MCE_PRESENT 0x00000008 // ONLY Pentium style MCE available
+
+extern ULONG HalpFeatureBits;
+
+//
+// Defines for Processor Features returned from CPUID instruction
+//
+
+#define CPUID_MCA_MASK 0x4000
+#define CPUID_MCE_MASK 0x0080
+
+
+NTSTATUS
+HalpGetMcaLog(
+ OUT PMCA_EXCEPTION Exception,
+ OUT PULONG ReturnedLength
+ );
+
+NTSTATUS
+HalpMcaRegisterDriver(
+ IN PMCA_DRIVER_INFO pMcaDriverInfo // Info about registering driver
+ );
+
+VOID
+HalpMcaInit(
+ VOID
+ );
+
+
+
+#endif // _HALP_
diff --git a/private/ntos/nthals/halx86/i386/ix8259.inc b/private/ntos/nthals/halx86/i386/ix8259.inc
new file mode 100644
index 000000000..d053fbc22
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ix8259.inc
@@ -0,0 +1,199 @@
+;/*
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; ix8259.inc
+;
+; Abstract:
+;
+; This module contains the definitions used by HAL to manipulate
+; 8259 interrupt controller and 8259-specific constants.
+;
+; WARNING: This file is included by both ASM and C files.
+;
+; Author:
+;
+; John Vert (jvert) 31-Dec-1991
+;
+; (Moved from ke\i386\kimacro.inc)
+;
+;--
+if 0 ; Begin C only code */
+
+//
+// 8259 defines for C code
+// BE SURE TO CHANGE THESE VALUES IN BOTH TABLES!
+//
+
+#define HIGHEST_LEVEL_FOR_8259 27 // Highest level for standard 8259
+#define PRIMARY_VECTOR_BASE 0x30 // Vector base for standard 8259
+#define PROFILE_VECTOR (PRIMARY_VECTOR_BASE + 8) // standard profile
+#define CLOCK_VECTOR (PRIMARY_VECTOR_BASE + 0) // standard clock
+#define I386_80387_IRQ 0x0d // standard npx
+#define I386_80387_IRQL (HIGHEST_LEVEL_FOR_8259 - I386_80387_IRQ)
+#define I386_80387_VECTOR (PRIMARY_VECTOR_BASE + I386_80387_IRQ)
+#define PIC_SLAVE_IRQ 2
+#define V2I(a) (a-PRIMARY_VECTOR_BASE) // Vector to interrupt macro
+
+/*
+endif
+
+;
+; Same 8259 defines for assemble code
+; BE SURE TO CHANGE THESE VALUES IN BOTH TABLES!
+;
+
+HIGHEST_LEVEL_FOR_8259 equ 27
+PRIMARY_VECTOR_BASE equ 30h
+PROFILE_VECTOR equ (PRIMARY_VECTOR_BASE + 8)
+CLOCK_VECTOR equ (PRIMARY_VECTOR_BASE + 0)
+I386_80387_IRQ equ 0dh
+I386_80387_IRQL equ (HIGHEST_LEVEL_FOR_8259 - I386_80387_IRQ)
+I386_80387_VECTOR equ (PRIMARY_VECTOR_BASE + I386_80387_IRQ)
+I386_80387_BUSY_PORT equ 0f0h ; port to dismiss busy error line
+PIC_SLAVE_IRQ equ 2
+
+
+;
+; The rest of the file are macros used in assemble only.
+;
+
+;++
+;
+; SET_8259_MASK
+;
+; Macro Description:
+;
+; This macro sets 8259 interrupt mask register with the mask
+; passed from eax register.
+;
+; Note: Currently, only two 8259s are support. As a result,
+; only ax contains valid mask.
+;
+; Arguments:
+;
+; (eax) = mask for setting 8259 interrupt mask register
+;
+;--
+
+SET_8259_MASK macro
+local a ; define local labels
+
+ out PIC1_PORT1, al ; set master 8259 mask
+ shr eax, 8 ; shift slave 8259 mask to al
+ out PIC2_PORT1, al ; set slave 8259 mask
+a:
+endm
+
+;
+; Interrupt controller register addresses
+;
+
+PIC1_PORT0 equ 020H
+PIC1_PORT1 equ 021H
+PIC2_PORT0 equ 0A0H
+PIC2_PORT1 equ 0A1H
+
+;
+; Commands for Interrupt controller
+;
+
+PIC1_EOI_MASK equ 060H
+PIC2_EOI equ 062H
+OCW2_NON_SPECIFIC_EOI equ 020H
+OCW2_SPECIFIC_EOI equ 060H
+OCW3_READ_ISR equ 0BH
+OCW3_READ_IRR equ 0AH
+
+
+;++
+;
+; IODELAY
+;
+; Macro Description:
+;
+; This macro simply does a jmp to next instruction to synchronize
+; IO port access.
+;
+; Arguments:
+;
+; None
+;
+;--
+
+IODELAY macro
+ jmp $+2
+endm
+
+
+;++
+;
+; PICDELAY
+;
+; Macro Description:
+;
+; This macro does an inb on interrupt mask register to provide the
+; time for 8259 to get stabled.
+;
+; Why do we need this?
+;
+; This is because:
+; . The 80386 has a delayed write to memory and delayed output to IO
+; capability and
+; . 8259 needs some time to settle
+;
+; It is possible for the actual output cycle to 8259 to occur after
+; the completion of instructions following the out instruction. For
+; example, the STI instruction after SET_MASK and dismiss interrupt
+; macros may complete before 8259 actually drops the interrupt. We don't
+; want this happen in MCA system.
+;
+; You may argue that most OEMS add about 450ns delay to solve the
+; back-to-back IO (delay) problem. But, remember that STI is not an IO
+; instruction.
+;
+; Arguments:
+;
+; None
+;
+; NOTE: * The content of AL will be destroyed on return.
+;
+;--
+
+PIC1DELAY macro
+ in al, PIC1_PORT1
+endm
+
+PIC2DELAY macro
+ in al, PIC2_PORT1
+endm
+
+;++
+;
+; SOFT_INTERRUPT_EXIT
+;
+; Macro Description:
+;
+; This macro is executed on return from the soft interrupt
+; service routine. Its function is to restore privileged processor
+; state, and continue thread execution.
+;
+; Arguments:
+;
+; (TOS) = previous irql
+; (TOS+4 ...) = machine_state frame
+;
+;--
+
+SOFT_INTERRUPT_EXIT macro
+
+ EXTRNP _HalpEndSoftwareInterrupt,1
+ cli
+ call _HalpEndSoftwareInterrupt@4 ; restore irql
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without EOI
+endm
+;*/
+
diff --git a/private/ntos/nthals/halx86/i386/ixbeep.asm b/private/ntos/nthals/halx86/i386/ixbeep.asm
new file mode 100644
index 000000000..0722ca9df
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixbeep.asm
@@ -0,0 +1,181 @@
+ title "Hal Beep"
+;++
+;
+;Copyright (c) 1991 Microsoft Corporation
+;
+;Module Name:
+;
+; ixbeep.asm
+;
+;Abstract:
+;
+; HAL routine to make noise. It needs to synchronize its access to the
+; 8254, since we also use the 8254 for the profiling interrupt.
+;
+;
+;Author:
+;
+; John Vert (jvert) 31-Jul-1991
+;
+;Revision History:
+;
+;--
+
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+include i386\kimacro.inc
+include mac386.inc
+ .list
+
+ extrn _Halp8254Lock:DWORD
+
+;
+; Defines used to program the i8254 for the speaker.
+;
+
+I8254_TIMER_CONTROL_PORT EQU 43h
+I8254_TIMER_DATA_PORT EQU 42h
+I8254_TIMER_CLOCK_IN EQU 1193167
+I8254_TIMER_TONE_MAX EQU 65536
+I8254_TIMER_CONTROL_SELECT EQU 0B6h
+SPEAKER_CONTROL_PORT EQU 61h
+SPEAKER_OFF_MASK EQU 0FCh
+SPEAKER_ON_MASK EQU 03h
+
+_TEXT$03 SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+ page ,132
+ subttl "HalMakeBeep"
+;++
+;
+; 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.
+;
+;--
+
+Frequency equ [ebp + 8]
+
+cPublicProc _HalMakeBeep , 1
+
+ push ebp ; save ebp
+ mov ebp, esp ;
+
+ push ebx ; save ebx
+Hmb10: pushfd ; save flags
+ cli ; disable interrupts
+
+ifndef NT_UP
+ lea eax, _Halp8254Lock
+ ACQUIRE_SPINLOCK eax,Hmb99
+endif
+
+ ;
+ ; Stop the speaker.
+ ;
+
+ in al, SPEAKER_CONTROL_PORT
+ jmp $+2
+ and al, SPEAKER_OFF_MASK
+ out SPEAKER_CONTROL_PORT, al
+ jmp $+2
+
+ ;
+ ; Calculate Tone: Tone = 1.193MHz / Frequency.
+ ; N.B. Tone must fit in 16 bits.
+ ;
+
+ mov ecx, DWORD PTR [Frequency] ; ecx <- frequency
+ or ecx, ecx ; (ecx) == 0?
+ je SHORT Hmb30 ; goto Hmb30
+
+ mov eax, I8254_TIMER_CLOCK_IN ; eax <- 1.193MHz, the clockin
+ ; for the speaker tone
+ sub edx, edx ; edx <- zero
+ div ecx ; eax <- 1.193MHz / frequency
+ cmp eax, I8254_TIMER_TONE_MAX ; (eax) < 2**16?
+ jb SHORT Hmb20 ; goto Hmb20
+
+ ;
+ ; Invalid frequency. Return FALSE.
+ ;
+
+ sub al, al
+ jmp SHORT Hmb40
+Hmb20:
+ ;
+ ; Program the 8254 with the calculated tone.
+ ;
+
+ push eax ; save Tone
+ mov al, I8254_TIMER_CONTROL_SELECT
+ out I8254_TIMER_CONTROL_PORT, al ; select timer control register
+ jmp $+2
+
+ pop eax ; restore Tone
+ out I8254_TIMER_DATA_PORT, al ; program 8254 with Tone lsb
+ jmp $+2
+ mov al, ah
+ out I8254_TIMER_DATA_PORT, al ; program 8254 with Tone msb
+ jmp $+2
+
+ ;
+ ; Turn the speaker on.
+ ;
+
+ in al, SPEAKER_CONTROL_PORT
+ jmp $+2
+ or al, SPEAKER_ON_MASK
+ out SPEAKER_CONTROL_PORT, al
+ jmp $+2
+
+Hmb30:
+ ;
+ ; Return TRUE.
+ ;
+
+ mov al, 1
+
+Hmb40:
+ifndef NT_UP
+ lea ebx, _Halp8254Lock
+ RELEASE_SPINLOCK ebx
+endif
+
+ popfd
+ pop ebx ; restore ebx
+ pop ebp ; restore ebp
+ stdRET _HalMakeBeep
+
+ifndef NT_UP
+
+Hmb99: popfd
+ SPIN_ON_SPINLOCK eax,<Hmb10>
+
+endif
+
+stdENDP _HalMakeBeep
+
+_TEXT$03 ends
+ end
diff --git a/private/ntos/nthals/halx86/i386/ixbusdat.c b/private/ntos/nthals/halx86/i386/ixbusdat.c
new file mode 100644
index 000000000..ca7205c68
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixbusdat.c
@@ -0,0 +1,373 @@
+/*++
+
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ ixhwsup.c
+
+Abstract:
+
+ This module contains the IoXxx routines for the NT I/O system that
+ are hardware dependent. Were these routines not hardware dependent,
+ they would reside in the iosubs.c module.
+
+Author:
+
+ Ken Reneris (kenr) July-28-1994
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#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
+ );
+
+ULONG HalpcGetCmosData (
+ IN PVOID BusHandler,
+ IN PVOID RootHandler,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+ULONG HalpcSetCmosData (
+ IN PVOID BusHandler,
+ IN PVOID RootHandler,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+ULONG HalpGetCmosData (
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Length
+ );
+
+ULONG HalpSetCmosData (
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Length
+ );
+
+HalpGetEisaData (
+ IN PVOID BusHandler,
+ IN PVOID RootHandler,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+
+//
+// Prototype for system bus handlers
+//
+
+NTSTATUS
+HalpAdjustEisaResourceList (
+ 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
+HalpGetEisaInterruptVector (
+ 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
+ );
+
+BOOLEAN
+HalpTranslateIsaBusAddress (
+ IN PVOID BusHandler,
+ IN PVOID RootHandler,
+ IN PHYSICAL_ADDRESS BusAddress,
+ IN OUT PULONG AddressSpace,
+ OUT PPHYSICAL_ADDRESS TranslatedAddress
+ );
+
+BOOLEAN
+HalpTranslateEisaBusAddress (
+ IN PVOID BusHandler,
+ IN PVOID RootHandler,
+ IN PHYSICAL_ADDRESS BusAddress,
+ IN OUT PULONG AddressSpace,
+ OUT PPHYSICAL_ADDRESS TranslatedAddress
+ );
+
+VOID
+HalpRegisterInternalBusHandlers (
+ VOID
+ );
+
+NTSTATUS
+HalpHibernateHal (
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler
+ );
+
+NTSTATUS
+HalpResumeHal (
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler
+ );
+
+#ifdef MCA
+//
+// Default functionality of MCA handlers is the same as the Eisa handlers,
+// just use them
+//
+
+#define HalpGetMCAInterruptVector HalpGetEisaInterruptVector
+#define HalpAdjustMCAResourceList HalpAdjustEisaResourceList;
+
+HalpGetPosData (
+ IN PVOID BusHandler,
+ IN PVOID RootHandler,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+
+#endif
+
+
+#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;
+
+#if 0
+ //
+ // Hibernate and resume the hal by getting notifications
+ // for when this bus is hibernated or resumed. Since it's
+ // the first bus to be added, it will be the last to hibernate
+ // and the first to resume
+ //
+
+ Bus->HibernateBus = HalpHibernateHal;
+ Bus->ResumeBus = HalpResumeHal;
+#endif
+
+ //
+ // Add handlers for Cmos config space.
+ //
+
+ Bus = HalpAllocateBusHandler (InterfaceTypeUndefined, Cmos, 0, -1, 0, 0);
+ Bus->GetBusData = HalpcGetCmosData;
+ Bus->SetBusData = HalpcSetCmosData;
+
+ Bus = HalpAllocateBusHandler (InterfaceTypeUndefined, Cmos, 1, -1, 0, 0);
+ Bus->GetBusData = HalpcGetCmosData;
+ Bus->SetBusData = HalpcSetCmosData;
+
+#ifndef MCA
+ //
+ // Build Isa/Eisa bus #0
+ //
+
+ Bus = HalpAllocateBusHandler (Eisa, EisaConfiguration, 0, Internal, 0, 0);
+ Bus->GetBusData = HalpGetEisaData;
+ Bus->GetInterruptVector = HalpGetEisaInterruptVector;
+ Bus->AdjustResourceList = HalpAdjustEisaResourceList;
+ Bus->TranslateBusAddress = HalpTranslateEisaBusAddress;
+
+ Bus = HalpAllocateBusHandler (Isa, ConfigurationSpaceUndefined, 0, Eisa, 0, 0);
+ Bus->GetBusData = HalpNoBusData;
+ Bus->BusAddresses->Memory.Limit = 0xFFFFFF;
+ Bus->TranslateBusAddress = HalpTranslateIsaBusAddress;
+
+#else
+
+ //
+ // Build MCA bus #0
+ //
+
+ Bus = HalpAllocateBusHandler (MicroChannel, Pos, 0, Internal, 0, 0);
+ Bus->GetBusData = HalpGetPosData;
+ Bus->GetInterruptVector = HalpGetMCAInterruptVector;
+ Bus->AdjustResourceList = HalpAdjustMCAResourceList;
+
+#endif
+
+ 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 = 0xFFFFFFFF;
+ Bus->BusAddresses->IO.Limit = 0xFFFF;
+ Bus->BusAddresses->IO.SystemAddressSpace = 1;
+ Bus->BusAddresses->PrefetchMemory.Base = 1;
+ }
+
+ return Bus;
+}
+
+
+//
+// C to Asm thunks for CMos
+//
+
+ULONG HalpcGetCmosData (
+ IN PBUS_HANDLER BusHandler,
+ IN PVOID RootHandler,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+{
+ // bugbug: this interface should be rev'ed to support non-zero offsets
+ if (Offset != 0) {
+ return 0;
+ }
+
+ return HalpGetCmosData (BusHandler->BusNumber, SlotNumber, Buffer, Length);
+}
+
+
+ULONG HalpcSetCmosData (
+ IN PBUS_HANDLER BusHandler,
+ IN PVOID RootHandler,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+{
+ // bugbug: this interface should be rev'ed to support non-zero offsets
+ if (Offset != 0) {
+ return 0;
+ }
+
+ return HalpSetCmosData (BusHandler->BusNumber, SlotNumber, Buffer, Length);
+}
diff --git a/private/ntos/nthals/halx86/i386/ixclock.asm b/private/ntos/nthals/halx86/i386/ixclock.asm
new file mode 100644
index 000000000..6abb583cb
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixclock.asm
@@ -0,0 +1,760 @@
+
+ title "Interval Clock Interrupt"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; ixclock.asm
+;
+; Abstract:
+;
+; This module implements the code necessary to field and process the
+; interval clock interrupt.
+;
+; Author:
+;
+; Shie-Lin Tzong (shielint) 12-Jan-1990
+;
+; Environment:
+;
+; Kernel mode only.
+;
+; Revision History:
+;
+; bryanwi 20-Sep-90
+;
+; Add KiSetProfileInterval, KiStartProfileInterrupt,
+; KiStopProfileInterrupt procedures.
+; KiProfileInterrupt ISR.
+; KiProfileList, KiProfileLock are delcared here.
+;
+; shielint 10-Dec-90
+; Add performance counter support.
+; Move system clock to irq8, ie we now use RTC to generate system
+; clock. Performance count and Profile use timer 1 counter 0.
+; The interval of the irq0 interrupt can be changed by
+; KiSetProfileInterval. Performance counter does not care about the
+; interval of the interrupt as long as it knows the rollover count.
+; Note: Currently I implemented 1 performance counter for the whole
+; i386 NT.
+;
+; John Vert (jvert) 11-Jul-1991
+; Moved from ke\i386 to hal\i386. Removed non-HAL stuff
+;
+; shie-lin tzong (shielint) 13-March-92
+; Move System clock back to irq0 and use RTC (irq8) to generate
+; profile interrupt. Performance counter and system clock use time1
+; counter 0 of 8254.
+;
+; Landy Wang (corollary!landy) 04-Dec-92
+; Move much code into separate modules for easy inclusion by various
+; HAL builds.
+;
+;--
+
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+include i386\ix8259.inc
+include i386\kimacro.inc
+include mac386.inc
+include i386\ixcmos.inc
+ .list
+
+ EXTRNP _KeUpdateSystemTime,0
+ EXTRNP Kei386EoiHelper,0,IMPORT
+ EXTRNP _KeSetTimeIncrement,2,IMPORT
+ EXTRNP _HalEndSystemInterrupt,2
+ EXTRNP _HalBeginSystemInterrupt,3
+ EXTRNP _HalpReleaseCmosSpinLock ,0
+ EXTRNP _HalpMcaQueueDpc, 0
+
+;
+; Constants used to initialize timer 0
+;
+
+TIMER1_DATA_PORT0 EQU 40H ; Timer1, channel 0 data port
+TIMER1_CONTROL_PORT0 EQU 43H ; Timer1, channel 0 control port
+TIMER2_DATA_PORT0 EQU 48H ; Timer1, channel 0 data port
+TIMER2_CONTROL_PORT0 EQU 4BH ; Timer1, channel 0 control port
+TIMER1_IRQ EQU 0 ; Irq 0 for timer1 interrupt
+
+COMMAND_8254_COUNTER0 EQU 00H ; Select count 0
+COMMAND_8254_RW_16BIT EQU 30H ; Read/Write LSB firt then MSB
+COMMAND_8254_MODE2 EQU 4 ; Use mode 2
+COMMAND_8254_BCD EQU 0 ; Binary count down
+COMMAND_8254_LATCH_READ EQU 0 ; Latch read command
+
+PERFORMANCE_FREQUENCY EQU 1193182
+
+;
+; ==== Values used for System Clock ====
+;
+
+
+_DATA SEGMENT DWORD PUBLIC 'DATA'
+
+;
+; The following array stores the per microsecond loop count for each
+; central processor.
+;
+
+;
+; 8254 spinlock.
+;
+ public _Halp8254Lock
+_Halp8254Lock dd 0
+
+
+ public HalpPerfCounterLow, HalpPerfCounterHigh
+ public HalpLastPerfCounterLow, HalpLastPerfCounterHigh
+HalpPerfCounterLow dd 0
+HalpPerfCounterHigh dd 0
+HalpLastPerfCounterLow dd 0
+HalpLastPerfCounterHigh dd 0
+
+ public HalpCurrentRollOver, HalpCurrentTimeIncrement
+HalpCurrentRollOver dd 0
+HalpCurrentTimeIncrement dd 0
+
+ public _HalpClockWork, _HalpClockSetMSRate, _HalpClockMcaQueueDpc
+_HalpClockWork label dword
+ _HalpClockSetMSRate db 0
+ _HalpClockMcaQueueDpc db 0
+ _bReserved1 db 0
+ _bReserved2 db 0
+
+;
+; Convert the interval to rollover count for 8254 Timer1 device.
+; Timer1 counts down a 16 bit value at a rate of 1.193181667M counts-per-sec.
+; (The main crystal freq is 14.31818, and this is a divide by 12)
+;
+; The best fit value closest to 10ms is 10.0144012689ms:
+; ROLLOVER_COUNT 11949
+; TIME_INCREMENT 100144
+; Calculated error is -.0109472 s/day
+;
+;
+; The following table contains 8254 values timer values to use at
+; any given ms setting from 1ms - 15ms. All values work out to the
+; same error per day (-.0109472 s/day).
+;
+
+ public HalpRollOverTable
+
+ ; RollOver Time
+ ; Count Increment MS
+HalpRollOverTable dd 1197, 10032 ; 1 ms
+ dd 2394, 20064 ; 2 ms
+ dd 3591, 30096 ; 3 ms
+ dd 4767, 39952 ; 4 ms
+ dd 5964, 49984 ; 5 ms
+ dd 7161, 60016 ; 6 ms
+ dd 8358, 70048 ; 7 ms
+ dd 9555, 80080 ; 8 ms
+ dd 10731, 89936 ; 9 ms
+ dd 11949, 100144 ; 10 ms
+ dd 13125, 110000 ; 11 ms
+ dd 14322, 120032 ; 12 ms
+ dd 15519, 130064 ; 13 ms
+ dd 16695, 139920 ; 14 ms
+ dd 17892, 149952 ; 15 ms
+
+TimeIncr equ 4
+RollOver equ 0
+
+ public HalpLargestClockMS, HalpNextMSRate, HalpPendingMSRate
+HalpLargestClockMS dd 15 ; Table goes to 15MS
+HalpNextMSRate dd 0
+HalpPendingMSRate dd 0
+
+_DATA ends
+
+
+INIT SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+ page ,132
+ subttl "Initialize Clock"
+;++
+;
+; VOID
+; HalpInitializeClock (
+; )
+;
+; Routine Description:
+;
+; This routine initialize system time clock using 8254 timer1 counter 0
+; to generate an interrupt at every 15ms interval at 8259 irq0.
+;
+; See the definitions of TIME_INCREMENT and ROLLOVER_COUNT if clock rate
+; needs to be changed.
+;
+; Arguments:
+;
+; None
+;
+; Return Value:
+;
+; None.
+;
+;--
+cPublicProc _HalpInitializeClock ,0
+
+ mov eax, PCR[PcPrcb]
+ cmp byte ptr [eax].PbCpuType, 4 ; 486 or better?
+ jc short @f ; no, skip
+
+ mov HalpLargestClockMS, 10 ; Limit 486's to 10MS
+@@:
+ mov eax, HalpLargestClockMS
+ mov ecx, HalpRollOverTable.TimeIncr
+ mov edx, HalpRollOverTable[eax*8-8].TimeIncr
+ mov eax, HalpRollOverTable[eax*8-8].RollOver
+
+ mov HalpCurrentTimeIncrement, edx
+
+;
+; (ecx) = Min time_incr
+; (edx) = Max time_incr
+; (eax) = max roll over count
+;
+
+ push eax
+ stdCall _KeSetTimeIncrement, <edx, ecx>
+ pop ecx
+
+ pushfd ; save caller's eflag
+ cli ; make sure interrupts are disabled
+
+;
+; Set clock rate
+; (ecx) = RollOverCount
+;
+
+ mov al,COMMAND_8254_COUNTER0+COMMAND_8254_RW_16BIT+COMMAND_8254_MODE2
+ out TIMER1_CONTROL_PORT0, al ;program count mode of timer 0
+ IoDelay
+ mov al, cl
+ out TIMER1_DATA_PORT0, al ; program timer 0 LSB count
+ IoDelay
+ mov al,ch
+ out TIMER1_DATA_PORT0, al ; program timer 0 MSB count
+
+ popfd ; restore caller's eflag
+ mov HalpCurrentRollOver, ecx ; Set RollOverCount & initialized
+
+ stdRET _HalpInitializeClock
+
+stdENDP _HalpInitializeClock
+
+INIT ends
+
+_TEXT$03 SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+ page ,132
+ subttl "Query Performance Counter"
+;++
+;
+; LARGE_INTEGER
+; KeQueryPerformanceCounter (
+; OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL
+; )
+;
+; Routine Description:
+;
+; This routine returns current 64-bit performance counter and,
+; optionally, the Performance Frequency.
+;
+; Note this routine can NOT be called at Profiling interrupt
+; service routine. Because this routine depends on IRR0 to determine
+; the actual count.
+;
+; Also note that the performace counter returned by this routine
+; is not necessary the value when this routine is just entered.
+; The value returned is actually the counter value at any point
+; between the routine is entered and is exited.
+;
+; Arguments:
+;
+; PerformanceFrequency [TOS+4] - optionally, supplies the address
+; of a variable to receive the performance counter frequency.
+;
+; Return Value:
+;
+; Current value of the performance counter will be returned.
+;
+;--
+
+
+;
+; Parameter definitions
+;
+
+KqpcFrequency EQU [esp+12] ; User supplied Performance Frequence
+
+cPublicProc _KeQueryPerformanceCounter ,1
+;
+; First check to see if the performance counter has been initialized yet.
+; Since the kernel debugger calls KeQueryPerformanceCounter to support the
+; !timer command, we need to return something reasonable before 8254
+; initialization has occured. Reading garbage off the 8254 is not reasonable.
+;
+ cmp HalpCurrentRollOver, 0
+ je Kqpc50
+
+ push ebx
+ push esi
+
+Kqpc01: pushfd
+ cli
+Kqpc20:
+
+;
+; Fetch the base value. Note that interrupts are off.
+;
+
+ mov ebx, HalpPerfCounterLow
+ mov esi, HalpPerfCounterHigh ; [esi:ebx] = Performance counter
+
+;
+; Fetch the current counter value from the hardware
+;
+
+ mov al, COMMAND_8254_LATCH_READ+COMMAND_8254_COUNTER0
+ ;Latch PIT Ctr 0 command.
+ out TIMER1_CONTROL_PORT0, al
+ IODelay
+ in al, TIMER1_DATA_PORT0 ;Read PIT Ctr 0, LSByte.
+ IODelay
+ movzx ecx,al ;Zero upper bytes of (ECX).
+ in al, TIMER1_DATA_PORT0 ;Read PIT Ctr 0, MSByte.
+ mov ch, al ;(CX) = PIT Ctr 0 count.
+
+;
+; Now enable interrupts such that if timer interrupt is pending, it can
+; be serviced and update the PerformanceCounter. Note that there could
+; be a long time between the sti and cli because ANY interrupt could come
+; in in between.
+;
+
+ popfd ; don't re-enable interrupts if
+ nop ; the caller had them off!
+ ; (kernel debugger calls this function
+ ; with interrupts disabled)
+
+ jmp $+2 ; allow interrupt in case counter
+ ; has wrapped
+
+ pushfd
+ cli
+
+;
+; Fetch the base value again.
+;
+; Note: it's possible that the counter wrapped before we read the value
+; and that the timer tick interrupt did not occur during while interrupts
+; where enabled. (ie, there's a delay between when the device raises the
+; interrupt and when the processor see it).
+;
+;
+; note *2 -
+
+
+ mov eax, HalpPerfCounterLow
+ mov edx, HalpPerfCounterHigh ; [edx:eax] = new counter value
+
+;
+; Compare the two reads of Performance counter. If they are different,
+; start over
+;
+
+ cmp eax, ebx
+ jne short Kqpc20
+ cmp edx, esi
+ jne short Kqpc20
+
+ neg ecx ; PIT counts down from 0h
+ add ecx, HalpCurrentRollOver
+ jnc short Kqpc60
+
+Kqpc30:
+ add eax, ecx
+ adc edx, 0 ; [edx:eax] = Final result
+
+ cmp edx, HalpLastPerfCounterHigh
+ jc short Kqpc70 ; jmp if edx < lastperfcounterhigh
+ jne short Kqpc35 ; jmp if edx > lastperfcounterhigh
+
+ cmp eax, HalpLastPerfCounterLow
+ jc short Kqpc70 ; jmp if eax < lastperfcounterlow
+
+Kqpc35:
+ mov HalpLastPerfCounterLow, eax
+ mov HalpLastPerfCounterHigh, edx
+
+ popfd ; restore interrupt flag
+
+;
+; Return the freq. if caller wants it.
+;
+
+ cmp dword ptr KqpcFrequency, 0 ; is it a NULL variable?
+ jz short Kqpc40 ; if z, yes, go exit
+
+ mov ecx, KqpcFrequency ; (ecx)-> Frequency variable
+ mov DWORD PTR [ecx], PERFORMANCE_FREQUENCY ; Set frequency
+ mov DWORD PTR [ecx+4], 0
+
+Kqpc40:
+ pop esi ; restore esi and ebx
+ pop ebx
+ stdRET _KeQueryPerformanceCounter
+
+
+Kqpc50:
+; Initialization hasn't occured yet, so just return zeroes.
+ mov eax, 0
+ mov edx, 0
+ stdRET _KeQueryPerformanceCounter
+
+Kqpc60:
+;
+; The current count is larger then the HalpCurrentRollOver. The only way
+; that could happen is if there is an interrupt in route to the processor
+; but it was not processed while interrupts were enabled.
+;
+ mov esi, [esp] ; (esi) = flags
+ mov ecx, HalpCurrentRollOver ; (ecx) = max possible value
+ popfd ; restore flags
+
+ test esi, EFLAGS_INTERRUPT_MASK
+ jnz Kqpc01 ; ints are enabled, problem should go away
+
+ pushfd ; fix stack
+ jmp short Kqpc30 ; ints are disabled, use max count (ecx)
+
+
+Kqpc70:
+;
+; The current count is smaller then the last returned count. The only way
+; this should occur is if there is an interrupt in route to the processor
+; which was not been processed.
+;
+
+ mov ebx, HalpLastPerfCounterLow
+ mov esi, HalpLastPerfCounterHigh
+
+ mov ecx, ebx
+ or ecx, esi ; is last returned value 0?
+ jz short Kqpc35 ; Yes, then just return what we have
+
+ ; sanity check - make sure count is not off by bogus amount
+ sub ebx, eax
+ sbb esi, edx
+ jnz short Kqpc75 ; off by bogus amount
+ cmp ebx, HalpCurrentRollOver
+ jg short Kqpc75 ; off by bogus amount
+
+ sub eax, ebx
+ sbb edx, esi ; (edx:eax) = last returned count
+
+ mov ecx, [esp] ; (ecx) = flags
+ popfd
+
+ test ecx, EFLAGS_INTERRUPT_MASK
+ jnz Kqpc01 ; ints enabled, problem should go away
+
+ pushfd ; fix stack
+ jmp Kqpc35 ; ints disabled, just return last count
+
+Kqpc75:
+ popfd
+ xor eax, eax ; reset bogus values
+ mov HalpLastPerfCounterLow, eax
+ mov HalpLastPerfCounterHigh, eax
+ jmp Kqpc01 ; go try again
+
+stdENDP _KeQueryPerformanceCounter
+
+;++
+;
+; 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.
+;--
+cPublicProc _HalCalibratePerformanceCounter,1
+ mov eax, [esp+4] ; ponter to Number
+ pushfd ; save previous interrupt state
+ cli ; disable interrupts (go to high_level)
+
+ lock dec dword ptr [eax] ; count down
+
+@@: cmp dword ptr [eax], 0 ; wait for all processors to signal
+ jnz short @b
+
+ ;
+ ; Nothing to calibrate on a UP machine...
+ ;
+
+ popfd ; restore interrupt flag
+ stdRET _HalCalibratePerformanceCounter
+
+stdENDP _HalCalibratePerformanceCounter
+
+
+
+ page ,132
+ subttl "System Clock Interrupt"
+;++
+;
+; Routine Description:
+;
+; This routine is entered as the result of an interrupt generated by CLOCK.
+; Its function is to dismiss the interrupt, raise system Irql to
+; CLOCK2_LEVEL, update performance counter and transfer control to the
+; standard system routine to update the system time and the execution
+; time of the current thread
+; and process.
+;
+; Arguments:
+;
+; None
+; Interrupt is disabled
+;
+; Return Value:
+;
+; Does not return, jumps directly to KeUpdateSystemTime, which returns
+;
+; Sets Irql = CLOCK2_LEVEL and dismisses the interrupt
+;
+;--
+ ENTER_DR_ASSIST Hci_a, Hci_t
+
+cPublicProc _HalpClockInterrupt ,0
+
+;
+; Save machine state in trap frame
+;
+
+ ENTER_INTERRUPT Hci_a, Hci_t
+
+;
+; (esp) - base of trap frame
+;
+
+ifdef MCA
+
+;
+; Special hack for MCA machines
+;
+
+ in al, 61h
+ jmp $+2
+ or al, 80h
+ out 61h, al
+ jmp $+2
+
+endif ; MCA
+
+
+;
+; Dismiss interrupt and raise irq level to clock2 level
+;
+
+Hci10:
+ push CLOCK_VECTOR
+ sub esp, 4 ; allocate space to save OldIrql
+ stdCall _HalBeginSystemInterrupt, <CLOCK2_LEVEL, CLOCK_VECTOR, esp>
+
+ or al,al ; check for spurious interrupt
+ jz Hci100
+
+;
+; Update performance counter
+;
+
+ xor ebx, ebx
+ mov eax, HalpCurrentRollOver
+ add HalpPerfCounterLow, eax ; update performace counter
+ adc HalpPerfCounterHigh, ebx
+
+;
+; Check for any more work
+;
+ mov eax, HalpCurrentTimeIncrement
+
+ cmp _HalpClockWork, ebx ; Any clock interrupt work desired?
+ jz _KeUpdateSystemTime@0 ; No, process tick
+
+ cmp _HalpClockMcaQueueDpc, bl
+ je short Hci20
+
+ mov _HalpClockMcaQueueDpc, bl
+
+;
+; Queue MCA Dpc
+;
+
+ push eax
+ stdCall _HalpMcaQueueDpc ; Queue MCA Dpc
+ pop eax
+
+
+Hci20:
+;
+; (esp) = OldIrql
+; (esp+4) = Vector
+; (esp+8) = base of trap frame
+; ebp = trap frame
+; eax = time increment
+; ebx = 0
+;
+ cmp _HalpClockSetMSRate, bl ; New clock rate desired?
+ jz _KeUpdateSystemTime@0 ; No, process tick
+
+
+;
+; Time of clock frequency is being changed. See if the 8254 was
+; was reprogrammed for a new rate during last tick
+;
+ cmp HalpPendingMSRate, ebx ; Was a new rate set durning last
+ jnz short Hci50 ; tick? Yes, go update globals
+
+Hci40:
+; (eax) = time increment for current tick
+
+;
+; A new clock rate needs to be set. Setting the rate here will
+; cause the tick after the next tick to be at the new rate.
+; (the next tick is already in progress by the 8254 and will occur
+; at the same rate as this tick)
+;
+ mov ebx, HalpNextMSRate
+ mov HalpPendingMSRate, ebx ; pending rate
+
+ mov ecx, HalpRollOverTable[ebx*8-8].RollOver
+
+;
+; Set clock rate
+; (ecx) = RollOverCount
+;
+ push eax ; save current tick's rate
+
+ mov al,COMMAND_8254_COUNTER0+COMMAND_8254_RW_16BIT+COMMAND_8254_MODE2
+ out TIMER1_CONTROL_PORT0, al ;program count mode of timer 0
+ IoDelay
+ mov al, cl
+ out TIMER1_DATA_PORT0, al ; program timer 0 LSB count
+ IoDelay
+ mov al,ch
+ out TIMER1_DATA_PORT0, al ; program timer 0 MSB count
+
+ pop eax
+
+;
+; (esp) = OldIrql
+; (esp+4) = Vector
+; (esp+8) = base of trap frame
+; ebp = trap frame
+; eax = time increment
+;
+ jmp _KeUpdateSystemTime@0 ; dispatch this tick
+
+Hci50:
+;
+; The next tick will occur at the rate which was programmed during the last
+; tick. Update globals for new rate which starts with the next tick.
+;
+; (eax) = time increment for current tick
+;
+ mov ebx, HalpPendingMSRate
+ mov ecx, HalpRollOverTable[ebx*8-8].RollOver
+ mov edx, HalpRollOverTable[ebx*8-8].TimeIncr
+
+ mov HalpCurrentRollOver, ecx
+ mov HalpCurrentTimeIncrement, edx ; next tick rate
+ mov HalpPendingMSRate, 0 ; no longer pending, clear it
+
+ cmp ebx, HalpNextMSRate ; new rate == NextRate?
+ jne short Hci40 ; no, go set new pending rate
+
+ mov _HalpClockSetMSRate, 0 ; all done setting new rate
+ jmp _KeUpdateSystemTime@0 ; dispatch this tick
+
+Hci100:
+ add esp, 8 ; spurious, no EndOfInterrupt
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+stdENDP _HalpClockInterrupt
+
+;++
+;
+; ULONG
+; HalSetTimeIncrement (
+; IN ULONG DesiredIncrement
+; )
+;
+; /*++
+;
+; Routine Description:
+;
+; This routine initialize system time clock to generate an
+; interrupt at every DesiredIncrement interval.
+;
+; Arguments:
+;
+; DesiredIncrement - desired interval between every timer tick (in
+; 100ns unit.)
+;
+; Return Value:
+;
+; The *REAL* time increment set.
+;--
+cPublicProc _HalSetTimeIncrement,1
+
+ mov eax, [esp+4] ; desired setting
+ xor edx, edx
+ mov ecx, 10000
+ div ecx ; round to MS
+
+ cmp eax, HalpLargestClockMS ; MS > max?
+ jc short @f
+ mov eax, HalpLargestClockMS ; yes, use max
+@@:
+ or eax, eax ; MS < min?
+ jnz short @f
+ inc eax ; yes, use min
+@@:
+ mov HalpNextMSRate, eax
+ mov _HalpClockSetMSRate, 1 ; New clock rate desired.
+
+ mov eax, HalpRollOverTable[eax*8-8].TimeIncr
+ stdRET _HalSetTimeIncrement
+
+stdENDP _HalSetTimeIncrement
+_TEXT$03 ends
+
+ end
diff --git a/private/ntos/nthals/halx86/i386/ixcmos.asm b/private/ntos/nthals/halx86/i386/ixcmos.asm
new file mode 100644
index 000000000..5cc391076
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixcmos.asm
@@ -0,0 +1,1135 @@
+ title "Cmos Access Routines"
+;++
+;
+; Module Name:
+;
+; ixcmos.asm
+;
+; Abstract:
+;
+; Procedures necessary to access CMOS/ECMOS information.
+;
+; Author:
+;
+; David Risner (o-ncrdr) 20 Apr 1992
+;
+; Revision History:
+;
+; Landy Wang (corollary!landy) 04 Dec 1992
+; - Move much code from ixclock.asm to here so different HALs
+; can reuse the common functionality.
+;
+;--
+
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+include mac386.inc
+include i386\ix8259.inc
+include i386\ixcmos.inc
+ .list
+
+ EXTRNP _DbgBreakPoint,0,IMPORT
+ extrn _HalpSystemHardwareLock:DWORD
+ extrn _HalpBusType:DWORD
+ extrn _HalpSerialLen:BYTE
+ extrn _HalpSerialNumber:BYTE
+
+
+CMOS_STATUS_BUSY EQU 80H ; Time update in progress
+RTC_OFFSET_SECOND EQU 0 ; second field of RTC memory
+RTC_OFFSET_MINUTE EQU 2 ; minute field of RTC memory
+RTC_OFFSET_HOUR EQU 4 ; hour field of RTC memory
+RTC_OFFSET_DAY_OF_WEEK EQU 6 ; day-of-week field of RTC memory
+RTC_OFFSET_DATE_OF_MONTH EQU 7 ; date-of-month field of RTC memory
+RTC_OFFSET_MONTH EQU 8 ; month field of RTC memory
+RTC_OFFSET_YEAR EQU 9 ; year field of RTC memory
+RTC_OFFSET_CENTURY_MCA EQU 37h ; Century field of RTC memory for MCA
+RTC_OFFSET_CENTURY EQU 32h ; Century field of RTC memory
+RTC_OFFSET_CENTURY_DS EQU 148h ; Bank 1, 48. Century field for DS
+BANK1 EQU 100h
+
+;
+; BCD_TO_BIN
+;
+; Description: Convert BCD value to binary
+;
+; Parameter:
+; Input: (AL) = 2 digit BCD number to convert
+; Output: (AX) = Binary equivalent (all in AL)
+;
+; Return: None.
+;
+
+BCD_TO_BIN macro
+
+ xor ah,ah
+ rol ax,4
+ ror al,4
+ aad
+endm
+
+;
+; BIN_TO_BCD
+;
+; Description: Convert binary value to BCD.
+;
+; Parameter:
+; Input: (AL) = binary value to be converted.
+; Output: (AX) = BCD (all in AL)
+;
+; Return: None.
+;
+
+BIN_TO_BCD macro
+
+ aam
+ rol al, 4
+ ror ax, 4
+endm
+
+
+_DATA SEGMENT DWORD PUBLIC 'DATA'
+
+;
+; HalpRebootNow is a reboot vector. Set in an MP system, to
+; cause any processors which may be looping in HalpAcquireCmosSinLock
+; to transfer control to the vector in HalpRebootNow
+;
+
+ public _HalpRebootNow
+_HalpRebootNow dd 0
+
+;
+; Holds the value of the eflags register before a cmos spinlock is
+; acquired (used in HalpAcquire/ReleaseCmosSpinLock().
+;
+_HalpHardwareLockFlags dd 0
+
+;
+; Holds the offset to CMOS Century information.
+;
+
+_HalpCmosCenturyOffset dd 0
+
+_DATA ends
+
+ subttl "HalpGetCmosData"
+
+;++
+;
+; CMOS space read and write functions.
+;
+;--
+
+CmosAddressPort equ 70H
+CmosDataPort equ 71H
+
+ECmosAddressLsbPort equ 74H
+ECmosAddressMsbPort equ 75H
+ECmosDataPort equ 76H
+
+
+INIT SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+;++
+;
+; VOID
+; HalpInitializeCmos(
+; VOID
+; )
+;
+; This routine reads CMOS and initializes globals required for
+; CMOS access, such as the location of the century byte.
+;
+;--
+
+cPublicProc _HalpInitializeCmos,0
+
+ push ebx
+ push esi
+ push edi
+
+;
+; Assume default
+;
+
+ mov eax, RTC_OFFSET_CENTURY
+ mov _HalpCmosCenturyOffset, eax
+
+ cmp _HalpBusType, MACHINE_TYPE_ISA
+ jne short icm40
+
+
+;
+; If control comes here, this is ISA machine. We need to check if this is
+; IBM PS/1 or Pc/ValuePoint machine and use RTC_CENTURY_OFFSET_MCA to get
+; Century byte from CMOS.
+;
+
+;
+; Check if the CMOS 2e and 2f contains memory checksum. On PS/1 machine
+; the check should fail.
+;
+
+icm20: mov ecx, 2dh ; from 10h to 2dh
+ mov eax, 0 ; clear ax
+ mov edx, 0
+
+icm30: mov al, cl
+ CMOS_READ
+ add edx, eax
+ dec ecx
+ cmp ecx, 0fh
+ jne short icm30
+
+ mov eax, 2eh
+ CMOS_READ
+ mov ah, al
+ mov al, 2fh
+ CMOS_READ
+ cmp eax, edx
+ je short icm50 ; NOT PS/1
+
+ mov eax, RTC_OFFSET_CENTURY_MCA
+ mov _HalpCmosCenturyOffset, eax
+ jmp icm90
+
+icm40: cmp _HalpBusType, MACHINE_TYPE_MCA
+ jne short icm50
+
+;
+; See if this is a P700 MCA machine
+;
+
+ in al, 07fh ; get PD700 ID byte
+ and al, 0F0h ; Mask high nibble
+ cmp al, 0A0h ; Is the ID Ax?
+ jz short icm50
+ cmp al, 090h ; Or an 9X?
+ jz short icm50 ; Yes, it's a 700
+
+ mov eax, RTC_OFFSET_CENTURY_MCA
+ mov _HalpCmosCenturyOffset, eax
+
+icm50:
+
+if 0
+
+ - Selecting BANK1 causes some devices to mess up their month value
+ - For now, I'm removing this code until this problem can be solved
+
+;
+; See if this is a Dallas Semiconductor DS17285 or later
+; Switch to BANK 1
+;
+ mov al, 0Ah
+ CMOS_READ
+
+ and al, 7fh ; Don't write UIP
+ mov ah, al
+ mov esi, eax ; save it for restore
+ or ah, 10h ; Set DV0 = 1
+
+ mov al, 0Ah ; Write register A
+ CMOS_WRITE
+
+;
+; Check for RTC serial # with matching crc
+; (al) = current byte
+; (ah) = scratch register
+; (bl) = current crc
+; (bh) = zero, non-zero, flag
+; (ecx) = cmos offset
+; (edx) = used by cmos_read macro
+; (esi) = saved register 0A
+;
+ mov ecx, 40h
+ xor ebx, ebx
+
+icm60: mov al, cl
+ CMOS_READ
+ mov byte ptr _HalpSerialNumber+2+-40h[ecx], al
+
+ or bh, al ; or to check for all zeros
+
+ mov ch, 8 ; Bits per byte
+
+icm65: mov ah, bl ; ah = crc
+ xor ah, al ; xor LSb
+ shr bl, 1 ; shift crc
+ shr ah, 1 ; mov LSb to carry
+ sbb ah, ah ; if carry set 1's else 0's
+ and ah, (118h shr 1) ; crc polynomial
+ xor bl, ah ; apply it
+
+ shr al, 1 ; next bit
+ dec ch ;
+ jnz short icm65 ; if ch non-zero, loop
+
+ inc cl ; next cmos location
+ cmp cl, 48h ; at end?
+ jne short icm60 ; no, loop
+;
+; (bh) = zero, non-zero flag
+; (bl) = crc
+;
+
+ mov eax, RTC_OFFSET_CENTURY_DS ; Read century byte
+ CMOS_READ
+
+ BCD_TO_BIN
+ movzx ecx, ax ; save it
+
+;
+; Switch back to BANK 0
+;
+
+ mov eax, esi
+ mov al, 0Ah
+ CMOS_WRITE
+
+;
+; Check for valid DS data
+;
+ cmp bh, 0 ; Was data all zeros?
+ je short icm90
+
+ cmp bl, 0 ; was CRC valid?
+ jnz short icm90
+
+ cmp ecx, 19 ; Is century before 19?
+ jb short icm90
+
+ cmp ecx, 20 ; Is century after 20?
+ ja short icm90
+
+;
+; Setup for DS century byte
+;
+ mov byte ptr _HalpSerialNumber+0, 'D'
+ mov byte ptr _HalpSerialNumber+1, 'S'
+ mov _HalpSerialLen, 10
+
+ mov eax, RTC_OFFSET_CENTURY_DS
+ mov _HalpCmosCenturyOffset, eax
+endif
+
+icm90: pop edi
+ pop esi
+ pop ebx
+ stdRET _HalpInitializeCmos
+
+stdENDP _HalpInitializeCmos
+
+
+INIT ends
+
+_TEXT SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+
+;++
+;
+; ULONG
+; HalpGetCmosData(
+; IN ULONG SourceLocation
+; IN ULONG SourceAddress
+; IN ULONG ReturnBuffer
+; IN PUCHAR ByteCount
+; )
+;
+; This routine reads the requested number of bytes from CMOS/ECMOS and
+; stores the data read into the supplied buffer in system memory. If
+; the requested data amount exceeds the allowable extent of the source
+; location, the return data is truncated.
+;
+; Arguments:
+;
+; SourceLocation : where data is to be read from CMOS or ECMOS
+; 0 - CMOS, 1 - ECMOS
+;
+; SourceAddress : address in CMOS/ECMOS where data is to be read from
+;
+; ReturnBuffer : address in system memory for return data
+;
+; ByteCount : number of bytes to be read
+;
+; Returns:
+;
+; Number of byte actually read.
+;
+;--
+
+SourceLocation equ 2*4[ebp]
+SourceAddress equ 3*4[ebp]
+ReturnBuffer equ 4*4[ebp]
+ByteCount equ 5*4[ebp]
+
+cPublicProc _HalpGetCmosData ,4
+
+ push ebp
+ mov ebp, esp
+ push ebx
+ push edi
+
+ ;
+ ; NOTE: The spinlock is needed even in the UP case, because
+ ; the resource is also used in an interrupt handler (profiler).
+ ; If we own the spinlock in this routine, and we service
+ ; the profiler interrupt (which will wait for the spinlock forever),
+ ; then we have a hosed system.
+ ;
+ stdCall _HalpAcquireCmosSpinLock
+
+ xor edx, edx ; initialize return data length
+ mov ecx, ByteCount
+
+ or ecx, ecx ; validate requested byte count
+ jz HalpGetCmosDataExit ; if no work to do, exit
+
+ mov edx, SourceAddress
+ mov edi, ReturnBuffer
+
+ mov eax, SourceLocation ; cmos or extended cmos?
+ cmp eax, 1
+ je ECmosReadByte
+ cmp eax, 0
+ jne HalpGetCmosDataExit
+
+CmosReadByte:
+ cmp edx, 0ffH ; validate cmos source address
+ ja HalpGetCmosDataExit ; if out of range, exit
+ mov al, dl
+ out CmosAddressPort, al
+ in al, CmosDataPort
+ mov [edi], al
+ inc edx
+ inc edi
+ dec ecx
+ jnz CmosReadByte
+ jmp SHORT HalpGetCmosDataExit
+
+ECmosReadByte:
+ cmp edx,0ffffH ; validate ecmos source address
+ ja HalpGetCmosDataExit ; if out of range, exit
+ mov al, dl
+ out ECmosAddressLsbPort, al
+ mov al, dh
+ out ECmosAddressMsbPort, al
+ in al, ECmosDataPort
+ mov [edi], al
+ inc edx
+ inc edi
+ dec ecx
+ jnz ECmosReadByte
+
+HalpGetCmosDataExit:
+ stdCall _HalpReleaseCmosSpinLock
+
+ mov eax, edx ; return bytes read
+
+ pop edi
+ pop ebx
+ pop ebp
+
+ stdRET _HalpGetCmosData
+
+stdENDP _HalpGetCmosData
+
+
+;++
+;
+; VOID
+; HalpSetCmosData(
+; IN ULONG SourceLocation
+; IN ULONG SourceAddress
+; IN ULONG ReturnBuffer
+; IN PUCHAR ByteCount
+; )
+;
+; This routine writes the requested number of bytes to CMOS/ECMOS
+;
+; Arguments:
+;
+; SourceLocation : where data is to be written to CMOS or ECMOS
+; 0 - CMOS, 1 - ECMOS
+;
+; SourceAddress : address in CMOS/ECMOS where data is to write to.
+;
+; ReturnBuffer : address in system memory for data to write
+;
+; ByteCount : number of bytes to be write
+;
+; Returns:
+;
+; Number of byte actually written.
+;
+;--
+
+cPublicProc _HalpSetCmosData ,4
+
+ push ebp
+ mov ebp, esp
+ push ebx
+ push edi
+
+ stdCall _HalpAcquireCmosSpinLock
+
+ xor edx, edx ; initialize return data length
+ mov ecx, ByteCount
+
+ or ecx, ecx ; validate requested byte count
+ jz HalpSetCmosDataExit ; if no work to do, exit
+
+ mov edx, SourceAddress
+ mov edi, ReturnBuffer
+
+ mov eax, SourceLocation ; cmos or extended cmos?
+ cmp eax, 1
+ je ECmosWriteByte
+ cmp eax, 0
+ jne HalpSetCmosDataExit
+
+CmosWriteByte:
+ cmp edx, 0ffH ; validate cmos source address
+ ja HalpSetCmosDataExit ; if out of range, exit
+ mov al, dl
+ out CmosAddressPort, al
+ mov al, [edi]
+ out CmosDataPort, al
+ inc edx
+ inc edi
+ dec ecx
+ jnz CmosWriteByte
+ jmp SHORT HalpSetCmosDataExit
+
+ECmosWriteByte:
+ cmp edx,0ffffH ; validate ecmos source address
+ ja HalpSetCmosDataExit ; if out of range, exit
+ mov al, dl
+ out ECmosAddressLsbPort, al
+ mov al, dh
+ out ECmosAddressMsbPort, al
+ mov al, [edi]
+ out ECmosDataPort, al
+ inc edx
+ inc edi
+ dec ecx
+ jnz ECmosWriteByte
+
+HalpSetCmosDataExit:
+ stdCall _HalpReleaseCmosSpinLock
+
+ mov eax, edx ; return bytes written
+ pop edi
+ pop ebx
+ pop ebp
+
+ stdRET _HalpSetCmosData
+
+stdENDP _HalpSetCmosData
+
+
+ page ,132
+ subttl "Read System Time"
+;++
+;
+; VOID
+; HalpReadCmosTime (
+; PTIME_FIELDS TimeFields
+; )
+;
+; Routine Description:
+;
+; This routine reads current time from CMOS memory and stores it
+; in the TIME_FIELDS structure passed in by caller.
+;
+; Arguments:
+;
+; TimeFields - A pointer to the TIME_FIELDS structure.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+;
+; Parameters:
+;
+
+KrctPTimeFields equ [esp+4]
+
+cPublicProc _HalpReadCmosTime ,1
+
+if DBG
+krctwait0:
+ mov ecx, 100
+krctwait:
+ push ecx
+else
+krctwait:
+endif
+ stdCall _HalpAcquireCmosSpinLock
+ mov ecx, 100
+ align 4
+krct00: mov al, 0Ah ; Specify register A
+ CMOS_READ ; (al) = CMOS register A
+ test al, CMOS_STATUS_BUSY ; Is time update in progress?
+ jz short krct10 ; if z, no, go read CMOS time
+ loop short krct00 ; otherwise, try again.
+
+;
+; CMOS is still busy. Try again ...
+;
+
+ stdCall _HalpReleaseCmosSpinLock
+if DBG
+ pop ecx
+ loop short krctwait
+ stdCall _DbgBreakPoint
+ jmp short krctwait0
+else
+ jmp short krctwait
+endif
+ align 4
+if DBG
+krct10:
+ pop ecx
+else
+krct10:
+endif
+ mov edx, KrctPTimeFields ; (edx)-> TIME_FIELDS structure
+ xor eax, eax ; (eax) = 0
+
+ mov al, RTC_OFFSET_SECOND
+ CMOS_READ ; (al) = second in BCD form
+ BCD_TO_BIN ; (ax) = second
+ mov [edx].TfSecond, ax ; set second in TIME_FIELDS
+
+ mov al, RTC_OFFSET_MINUTE
+ CMOS_READ ; (al) = minute in BCD form
+ BCD_TO_BIN ; (ax) = Minute
+ mov [edx].TfMinute, ax ; set minute in TIME_FIELDS
+
+ mov al, RTC_OFFSET_HOUR
+ CMOS_READ ; (al) = hour in BCD form
+ BCD_TO_BIN ; (ax) = Hour
+ mov [edx].TfHour, ax ; set hour in TIME_FIELDS
+
+ mov al, RTC_OFFSET_DAY_OF_WEEK
+ CMOS_READ ; (al) = day-of-week in BCD form
+ BCD_TO_BIN ; (ax) = day-of-week
+ mov [edx].TfWeekday, ax ; set Weekday in TIME_FIELDS
+
+ mov al, RTC_OFFSET_DATE_OF_MONTH
+ CMOS_READ ; (al) = date-of-month in BCD form
+ BCD_TO_BIN ; (ax) = date_of_month
+ mov [edx].TfDay, ax ; set day in TIME_FIELDS
+
+ mov al, RTC_OFFSET_MONTH
+ CMOS_READ ; (al) = month in BCD form
+ BCD_TO_BIN ; (ax) = month
+ mov [edx].TfMonth, ax ; set month in TIME_FIELDS
+
+ mov al, RTC_OFFSET_YEAR
+ CMOS_READ ; (al) = year in BCD form
+ BCD_TO_BIN ; (ax) = year
+ push eax ; save year in stack
+
+ push edx ; preserve edx
+ call _HalpGetCmosCenturyByte ; (al)= century byte in BCD form
+ BCD_TO_BIN ; (ax) = century
+ pop edx
+
+ mov ah, 100
+ mul ah ; (ax) = century * 100
+ pop ecx ; (cx) = year
+ add ax, cx ; (ax)= year
+
+ cmp ax, 1900 ; Is year > 1900
+ jb short krct40
+ cmp ax, 1920 ; and < 1920
+ jae short krct40
+ add ax, 100 ; Compensate for century field
+
+krct40:
+ mov [edx].TfYear, ax ; set year in TIME_FIELDS
+
+ mov word ptr [edx].TfMilliseconds, 0 ; do not support
+
+ stdCall _HalpReleaseCmosSpinLock
+
+ stdRET _HalpReadCmosTime
+
+stdENDP _HalpReadCmosTime
+
+ page ,132
+ subttl "Write System Time"
+;++
+;
+; VOID
+; HalpWriteCmosTime (
+; PTIME_FIELDS TimeFields
+; )
+;
+; Routine Description:
+;
+; This routine writes current time from TIME_FILEDS structure
+; to CMOS memory.
+;
+; Arguments:
+;
+; TimeFields - A pointer to the TIME_FIELDS structure.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+;
+; Parameters:
+;
+
+KrctPTimeFields equ [esp+4]
+
+cPublicProc _HalpWriteCmosTime ,1
+
+if DBG
+kwctwait0:
+ mov ecx, 100
+kwctwait:
+ push ecx
+else
+kwctwait:
+endif
+ stdCall _HalpAcquireCmosSpinLock
+ mov ecx, 100
+ align 4
+kwct00: mov al, 0Ah ; Specify register A
+ CMOS_READ ; (al) = CMOS register A
+ test al, CMOS_STATUS_BUSY ; Is time update in progress?
+ jz short kwct10 ; if z, no, go write CMOS time
+ loop short kwct00 ; otherwise, try again.
+
+;
+; CMOS is still busy. Try again ...
+;
+
+ stdCall _HalpReleaseCmosSpinLock
+if DBG
+ pop ecx
+ loop short kwctwait
+ stdCall _DbgBreakPoint
+ jmp short kwctwait0
+else
+ jmp short kwctwait
+endif
+ align 4
+if DBG
+kwct10:
+ pop ecx
+else
+kwct10:
+endif
+ mov edx, KrctPTimeFields ; (edx)-> TIME_FIELDS structure
+
+ mov al, [edx].TfSecond ; Read second in TIME_FIELDS
+ BIN_TO_BCD
+ mov ah, al
+ mov al, RTC_OFFSET_SECOND
+ CMOS_WRITE
+
+ mov al, [edx].TfMinute ; Read minute in TIME_FIELDS
+ BIN_TO_BCD
+ mov ah, al
+ mov al, RTC_OFFSET_MINUTE
+ CMOS_WRITE
+
+ mov al, [edx].TfHour ; Read Hour in TIME_FIELDS
+ BIN_TO_BCD
+ mov ah, al
+ mov al, RTC_OFFSET_HOUR
+ CMOS_WRITE
+
+ mov al, [edx].TfWeekDay ; Read WeekDay in TIME_FIELDS
+ BIN_TO_BCD
+ mov ah, al
+ mov al, RTC_OFFSET_DAY_OF_WEEK
+ CMOS_WRITE
+
+ mov al, [edx].TfDay ; Read day in TIME_FIELDS
+ BIN_TO_BCD
+ mov ah, al
+ mov al, RTC_OFFSET_DATE_OF_MONTH
+ CMOS_WRITE
+
+ mov al, [edx].TfMonth ; Read month in TIME_FIELDS
+ BIN_TO_BCD
+ mov ah, al
+ mov al, RTC_OFFSET_MONTH
+ CMOS_WRITE
+
+ mov ax, [edx].TfYear ; Read Year in TIME_FIELDS
+ cmp ax, 9999
+ jbe short kwct15
+ mov ax, 9999
+
+ align 4
+kwct15:
+ mov cl, 100
+ div cl ; [ax]/[cl]->al=quo, ah=rem
+ push eax
+ BIN_TO_BCD
+
+ push eax
+ call _HalpSetCmosCenturyByte
+
+ pop eax
+ mov al, ah ; [al] = Year
+ BIN_TO_BCD
+ mov ah, al ; [ah] = year in BCD
+ mov al, RTC_OFFSET_YEAR
+ CMOS_WRITE
+
+ stdCall _HalpReleaseCmosSpinLock
+
+ stdRET _HalpWriteCmosTime
+
+stdENDP _HalpWriteCmosTime
+
+
+;++
+;
+; Routine Description:
+;
+; Acquires a spinlock to access the cmos chip. The cmos chip is
+; accessed at different irql levels, so to be safe, we 'cli'.
+; We could replace that to raise irql to PROFILE_LEVEL, but that's
+; a lot of code.
+;
+; Arguments:
+;
+; None
+;
+; Return Value:
+;
+; Interrupt is disabled.
+; Irql level not affected.
+; Flags saved in _HalpHardwareLockFlags.
+;--
+
+cPublicProc _HalpAcquireCmosSpinLock ,0
+ push eax
+
+Arsl10: pushfd
+ cli
+ lea eax, _HalpSystemHardwareLock
+ ACQUIRE_SPINLOCK eax, Arsl20
+ pop _HalpHardwareLockFlags ; save flags for release S.L.
+ pop eax
+ stdRET _HalpAcquireCmosSpinLock
+
+Arsl20: popfd
+
+Arsl30:
+ifndef NT_UP
+ cmp _HalpRebootNow, 0
+ jnz short Arsl50
+endif
+ TEST_SPINLOCK eax, <short Arsl30>
+ jmp short ARsl10
+
+Arsl50:
+ifndef NT_UP
+ mov eax, _HalpRebootNow
+ call eax
+ int 3 ; should not return
+endif
+
+stdENDP _HalpAcquireCmosSpinLock
+
+
+;++
+;
+; Routine Description:
+;
+; Release spinlock, and restore flags to the state it was before
+; acquiring the spinlock.
+;
+; Arguments:
+;
+; None
+;
+; Return Value:
+;
+; Interrupts restored to their state before acquiring spinlock.
+; Irql level not affected.
+;
+;--
+
+cPublicProc _HalpReleaseCmosSpinLock ,0
+ push eax
+ ;
+ ; restore eflags as it was before acquiring spinlock. Put it on
+ ; stack before releasing spinlock (so other cpus cannot overwrite
+ ; it with their own eflags).
+ ;
+ push _HalpHardwareLockFlags ; old eflags on stack.
+ lea eax, _HalpSystemHardwareLock
+ RELEASE_SPINLOCK eax
+ popfd ; restore eflags.
+ pop eax
+ stdRET _HalpReleaseCmosSpinLock
+stdENDP _HalpReleaseCmosSpinLock
+
+;++
+;
+; UCHAR
+; HalpGetCmosCenturyByte (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This routine gets Century byte from CMOS.
+;
+; Arguments:
+;
+; None
+;
+; Return Value:
+;
+; (al) = Century byte in BCD form.
+;
+;--
+
+cPublicProc _HalpGetCmosCenturyByte, 0
+
+ mov eax, _HalpCmosCenturyOffset
+
+if DBG
+
+;
+; Make sure the HalpCmosCenturyOffset is initialized
+;
+
+ cmp eax, 0
+ jne short @f
+
+ int 3
+@@:
+endif
+ test eax, BANK1
+ jnz short rcb50
+
+ CMOS_READ ; (al) = century in BCD form
+ stdRET _HalpGetCmosCenturyByte
+
+rcb50: mov edx, eax
+
+ mov al, 0Ah
+ CMOS_READ
+
+ mov dh, al ; save it for restore
+ or al, 10h ; Set DV0 = 1
+
+ mov ah, al
+ mov al, 0Ah ; Write register A
+ CMOS_WRITE
+
+ mov al, dl ; century offset
+ CMOS_READ
+ mov dl, al ; save it
+
+ mov ah, dh ; Restore DV0
+ mov al, 0Ah ; Write register A
+ CMOS_WRITE
+
+ mov al, dl
+ stdRET _HalpGetCmosCenturyByte
+
+stdENDP _HalpGetCmosCenturyByte
+
+
+;++
+;
+; VOID
+; HalpSetCmosCenturyByte (
+; UCHAR Century
+; )
+;
+; Routine Description:
+;
+; This routine sets Century byte in CMOS.
+;
+; Arguments:
+;
+; Century - Supplies the value for CMOS century byte
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+cPublicProc _HalpSetCmosCenturyByte, 1
+
+ mov eax, _HalpCmosCenturyOffset
+if DBG
+
+;
+; Make sure the HalpCmosCenturyOffset is initialized
+;
+
+ cmp eax, 0
+ jne short @f
+
+ int 3
+@@:
+endif
+
+ test eax, BANK1
+ jnz short scb50
+
+ mov ah, [esp+4] ; (ah) = Century in BCD form
+ CMOS_WRITE
+ stdRET _HalpSetCmosCenturyByte
+
+
+scb50: mov edx, eax
+
+ mov al, 0Ah
+ CMOS_READ
+
+ mov dh, al ; save it for restore
+ or al, 10h ; Set DV0 = 1
+
+ mov ah, al
+ mov al, 0Ah ; Write register A
+ CMOS_WRITE
+
+ mov ah, [esp+4] ; (ah) = Century in BCD form
+ mov al, dl ; century offset
+ CMOS_WRITE
+
+ mov ah, dh ; Restore DV0
+ mov al, 0Ah ; Write register A
+ CMOS_WRITE
+ stdRET _HalpSetCmosCenturyByte
+
+stdENDP _HalpSetCmosCenturyByte
+
+
+;++
+;
+; VOID
+; HalpCpuID (
+; ULONG InEax,
+; PULONG OutEax,
+; PULONG OutEbx,
+; PULONG OutEcx,
+; PULONG OutEdx
+; );
+;
+; Routine Description:
+;
+; Executes the CPUID instruction and returns the registers from it
+;
+; Only available at INIT time
+;
+; Arguments:
+;
+; Return Value:
+;
+;--
+cPublicProc _HalpCpuID,5
+
+ push ebx
+ push esi
+
+ mov eax, [esp+12]
+ db 0fh, 0a2h ; CPUID
+
+ mov esi, [esp+16] ; return EAX
+ mov [esi], eax
+
+ mov esi, [esp+20] ; return EBX
+ mov [esi], ebx
+
+ mov esi, [esp+24] ; return ECX
+ mov [esi], ecx
+
+ mov esi, [esp+28] ; return EDX
+ mov [esi], edx
+
+ pop esi
+ pop ebx
+
+ stdRET _HalpCpuID
+
+stdENDP _HalpCpuID
+
+
+;++
+;
+; VOID
+; HalpFlushTLB (
+; VOID
+; );
+;
+; Routine Description:
+;
+; Flush the current TLB.
+;
+; Arguments:
+;
+; Return Value:
+;
+;--
+cPublicProc _HalpFlushTLB, 0
+.586p
+ pushfd
+ push ebx
+ push esi
+
+ cli
+ mov esi, cr3
+
+ mov ecx, PCR[PcPrcb]
+ cmp byte ptr [ecx].PbCpuID, 0
+ jz short ftb50
+
+ mov eax, 1 ; Get feature bits
+ cpuid ; (note "cpuid" between CR3 reload fixes
+ ; P6 B step errata #11)
+
+ test edx, 2000h ; see if 'G' bit is supported
+ jz short ftb50
+
+ mov ecx, cr4 ; 'G' bit is supported, due global flush
+ mov edx, ecx ; Save orginal cr4
+ and ecx, not CR4_PGE ; Make sure global bit is disabled
+ mov cr4, ecx
+ mov cr3, esi ; flush TLB
+ mov cr4, edx ; restore cr4
+ jmp short ftp99
+
+ftb50: mov cr3, esi
+
+ftp99: pop esi
+ pop ebx
+ popfd
+ stdRET _HalpFlushTLB
+
+.486p
+stdENDP _HalpFlushTLB
+
+
+_TEXT ends
+
+ end
diff --git a/private/ntos/nthals/halx86/i386/ixcmos.inc b/private/ntos/nthals/halx86/i386/ixcmos.inc
new file mode 100644
index 000000000..1f78de8e7
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixcmos.inc
@@ -0,0 +1,66 @@
+;/*
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; ixcmos.inc
+;
+; Abstract:
+;
+; This module contains common definitions used by the CMOS.
+;
+; Author:
+;
+; Landy Wang (corollary!landy) 04-Dec-1992
+;
+; (Moved from ixclock.asm)
+;
+;--
+
+;
+; _HalpAcquireCmosSpinLock and _HalpReleaseCmosSpinLock
+; must be called before accessing the CMOS in both uniprocessor
+; and multiprocessor systems.
+
+RTCIRQ EQU 8 ; IRQ number for RTC interrupt
+CMOS_CONTROL_PORT EQU 70h ; command port for cmos
+CMOS_DATA_PORT EQU 71h ; cmos data port
+
+;
+; CMOS_READ
+;
+; Description: This macro reads a byte from the CMOS register specified
+; in (AL).
+;
+; Parameter: (AL) = address/register to read
+; Returns: (AL) = data
+;
+
+CMOS_READ MACRO
+ OUT CMOS_CONTROL_PORT,al ; ADDRESS LOCATION AND DISABLE NMI
+ IODelay ; I/O DELAY
+ IN AL,CMOS_DATA_PORT ; READ IN REQUESTED CMOS DATA
+ IODelay ; I/O DELAY
+ENDM
+
+;
+; CMOS_WRITE
+;
+; Description: This macro reads a byte from the CMOS register specified
+; in (AL).
+;
+; Parameter: (AL) = address/register to read
+; (AH) = data to be written
+;
+; Return: None
+;
+
+CMOS_WRITE MACRO
+ OUT CMOS_CONTROL_PORT,al ; ADDRESS LOCATION AND DISABLE NMI
+ IODelay ; I/O DELAY
+ MOV AL,AH ; (AL) = DATA
+ OUT CMOS_DATA_PORT,AL ; PLACE IN REQUESTED CMOS LOCATION
+ IODelay ; I/O DELAY
+ENDM
diff --git a/private/ntos/nthals/halx86/i386/ixdat.c b/private/ntos/nthals/halx86/i386/ixdat.c
new file mode 100644
index 000000000..f6bc9cee3
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixdat.c
@@ -0,0 +1,159 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ixdat.c
+
+Abstract:
+
+ Declares various data which is initialize data, or pagable data.
+
+Author:
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#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 HalpDefaultPcIoSpace = {
+ NULL, CmResourceTypePort, InternalUsage,
+ {
+#ifndef MCA
+ 0x000, 0x10, // ISA DMA
+ 0x0C0, 0x10, // ISA DMA
+#else
+ 0x000, 0x20, // MCA DMA
+ 0x0C0, 0x20, // MCA DMA
+#endif
+ 0x080, 0x10, // DMA
+
+ 0x020, 0x2, // PIC
+ 0x0A0, 0x2, // Cascaded PIC
+
+ 0x040, 0x4, // Timer1, Referesh, Speaker, Control Word
+ 0x048, 0x4, // Timer2, Failsafe
+
+ 0x061, 0x1, // NMI (system control port B)
+ 0x092, 0x1, // system control port A
+
+ 0x070, 0x2, // Cmos/NMI enable
+#ifdef MCA
+ 0x074, 0x3, // Extended CMOS
+
+ 0x090, 0x2, // Arbritration Control Port, Card Select Feedback
+ 0x093, 0x2, // Reserved, System board setup
+ 0x096, 0x2, // POS channel select
+#endif
+ 0x0F0, 0x10, // coprocessor ports
+ 0,0
+ }
+};
+
+ADDRESS_USAGE HalpEisaIoSpace = {
+ NULL, CmResourceTypePort, InternalUsage,
+ {
+ 0x0D0, 0x10, // DMA
+ 0x400, 0x10, // DMA
+ 0x480, 0x10, // DMA
+ 0x4C2, 0xE, // DMA
+ 0x4D4, 0x2C, // DMA
+
+ 0x461, 0x2, // Extended NMI
+ 0x464, 0x2, // Last Eisa Bus Muster granted
+
+ 0x4D0, 0x2, // edge/level control registers
+
+ 0xC84, 0x1, // System board enable
+ 0, 0
+ }
+};
+
+//
+// Strings used for boot.ini options
+// from mphal.c
+//
+
+UCHAR HalpSzBreak[] = "BREAK";
+UCHAR HalpSzPciLock[] = "PCILOCK";
+
+//
+// From ixcmos.asm
+//
+
+UCHAR HalpSerialLen;
+UCHAR HalpSerialNumber[31];
+
+//
+// From usage.c
+//
+
+WCHAR HalpSzSystem[] = L"\\Registry\\Machine\\Hardware\\Description\\System";
+WCHAR HalpSzSerialNumber[] = L"Serial Number";
+
+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";
+
+//
+// From ixinfo.c
+//
+
+WCHAR rgzSuspendCallbackName[] = L"\\Callback\\SuspendHibernateSystem";
+UCHAR HalpGenuineIntel[]= "GenuineIntel";
+
+//
+// From ixmca.c
+//
+UCHAR MsgMCEPending[] = MSG_MCE_PENDING;
+WCHAR rgzSessionManager[] = L"Session Manager";
+WCHAR rgzEnableMCE[] = L"EnableMCE";
+WCHAR rgzEnableMCA[] = L"EnableMCA";
+
+
+#ifdef ALLOC_DATA_PRAGMA
+#pragma data_seg()
+#endif
+
+ULONG HalpFeatureBits;
+
+//
+// IDT vector usage info
+//
+
+IDTUsage HalpIDTUsage[MAXIMUM_IDTVECTOR+1];
diff --git a/private/ntos/nthals/halx86/i386/ixenvirv.c b/private/ntos/nthals/halx86/i386/ixenvirv.c
new file mode 100644
index 000000000..62bdccf01
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixenvirv.c
@@ -0,0 +1,183 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ixenvirv.c
+
+Abstract:
+
+ This module implements the HAL get and set environment variable routines
+ for a x86 system.
+
+ Note that this particular implementation only supports the LastKnownGood
+ environment variable. This is done by using the Daylight Savings Time
+ bit in the Real Time Clock NVRAM. (Not pretty, but it's all we've got)
+
+ Attempts to read or write any environment variable other than
+ LastKnownGood will fail.
+
+Author:
+
+ John Vert (jvert) 22-Apr-1992
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "arc.h"
+#include "arccodes.h"
+#include "string.h"
+
+#define CMOS_CONTROL_PORT ((PUCHAR)0x70)
+#define CMOS_DATA_PORT ((PUCHAR)0x71)
+#define CMOS_STATUS_B 0x0B
+#define CMOS_DAYLIGHT_BIT 1
+
+
+ARC_STATUS
+HalGetEnvironmentVariable (
+ IN PCHAR Variable,
+ IN USHORT Length,
+ OUT PCHAR Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ This function locates an environment variable and returns its value.
+
+ The only environment variable this implementation supports is
+ "LastKnownGood" It uses the Daylight Savings Time bit in the Real
+ TimeClock to indicate the state (TRUE/FALSE only) of this environment
+ variable.
+
+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.
+
+--*/
+
+{
+ UCHAR StatusByte;
+
+ UNREFERENCED_PARAMETER( Length );
+ UNREFERENCED_PARAMETER( Buffer );
+
+ if (_stricmp(Variable, "LastKnownGood") != 0) {
+ return ENOENT;
+ }
+
+ //
+ // Read the Daylight Savings Bit out of the RTC to determine whether
+ // the LastKnownGood environment variable is TRUE or FALSE.
+ //
+
+ HalpAcquireCmosSpinLock();
+ WRITE_PORT_UCHAR(CMOS_CONTROL_PORT, CMOS_STATUS_B);
+ StatusByte = READ_PORT_UCHAR(CMOS_DATA_PORT);
+ HalpReleaseCmosSpinLock ();
+
+ if (StatusByte & CMOS_DAYLIGHT_BIT) {
+ strncpy(Buffer, "TRUE", Length);
+ } else {
+ strncpy(Buffer, "FALSE", Length);
+ }
+
+ return ESUCCESS;
+}
+
+ARC_STATUS
+HalSetEnvironmentVariable (
+ IN PCHAR Variable,
+ IN PCHAR Value
+ )
+
+/*++
+
+Routine Description:
+
+ This function creates an environment variable with the specified value.
+
+ The only environment variable this implementation supports is
+ "LastKnownGood" It uses the Daylight Savings Time bit in the Real
+ TimeClock to indicate the state (TRUE/FALSE only) of this environment
+ variable.
+
+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.
+
+--*/
+
+{
+ UCHAR StatusByte;
+
+ if (_stricmp(Variable, "LastKnownGood") != 0) {
+ return ENOMEM;
+ }
+
+ if (_stricmp(Value, "TRUE") == 0) {
+
+ HalpAcquireCmosSpinLock();
+ //
+ // Turn Daylight Savings Bit on.
+ //
+ WRITE_PORT_UCHAR(CMOS_CONTROL_PORT, CMOS_STATUS_B);
+ StatusByte = READ_PORT_UCHAR(CMOS_DATA_PORT);
+
+ StatusByte |= CMOS_DAYLIGHT_BIT;
+
+ WRITE_PORT_UCHAR(CMOS_CONTROL_PORT, CMOS_STATUS_B);
+ WRITE_PORT_UCHAR(CMOS_DATA_PORT, StatusByte);
+
+ HalpReleaseCmosSpinLock();
+
+ } else if (_stricmp(Value, "FALSE") == 0) {
+
+ HalpAcquireCmosSpinLock();
+
+ //
+ // Turn Daylight Savings Bit off.
+ //
+
+ WRITE_PORT_UCHAR(CMOS_CONTROL_PORT, CMOS_STATUS_B);
+ StatusByte = READ_PORT_UCHAR(CMOS_DATA_PORT);
+
+ StatusByte &= ~CMOS_DAYLIGHT_BIT;
+
+ WRITE_PORT_UCHAR(CMOS_CONTROL_PORT, CMOS_STATUS_B);
+ WRITE_PORT_UCHAR(CMOS_DATA_PORT, StatusByte);
+
+ HalpReleaseCmosSpinLock();
+
+ } else {
+ return(ENOMEM);
+ }
+
+ return ESUCCESS;
+}
diff --git a/private/ntos/nthals/halx86/i386/ixfirm.c b/private/ntos/nthals/halx86/i386/ixfirm.c
new file mode 100644
index 000000000..1ebf1032a
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixfirm.c
@@ -0,0 +1,79 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ixreboot.c
+
+Abstract:
+
+ Provides the interface to the firmware for x86. Since there is no
+ firmware to speak of on x86, this is just reboot support.
+
+Author:
+
+ John Vert (jvert) 12-Aug-1991
+
+Revision History:
+
+--*/
+#include "halp.h"
+
+//
+// Defines to let us diddle the CMOS clock and the keyboard
+//
+
+#define CMOS_CTRL (PUCHAR )0x70
+#define CMOS_DATA (PUCHAR )0x71
+
+#define RESET 0xfe
+#define KEYBPORT (PUCHAR )0x64
+
+VOID HalpVideoReboot(VOID);
+VOID HalpReboot(VOID);
+
+
+VOID
+HalReturnToFirmware(
+ IN FIRMWARE_ENTRY Routine
+ )
+
+/*++
+
+Routine Description:
+
+ Returns control to the firmware routine specified. Since the x86 has
+ no useful firmware, it just stops the system.
+
+Arguments:
+
+ Routine - Supplies a value indicating which firmware routine to invoke.
+
+Return Value:
+
+ Does not return.
+
+--*/
+
+{
+ switch (Routine) {
+ case HalHaltRoutine:
+ case HalPowerDownRoutine:
+ case HalRestartRoutine:
+ case HalRebootRoutine:
+
+ HalpVideoReboot();
+
+ //
+ // Never returns
+ //
+
+ HalpReboot();
+ break;
+ default:
+ DbgPrint("HalReturnToFirmware called\n");
+ DbgBreakPoint();
+ break;
+ }
+}
diff --git a/private/ntos/nthals/halx86/i386/ixhwsup.c b/private/ntos/nthals/halx86/i386/ixhwsup.c
new file mode 100644
index 000000000..b0f89592d
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixhwsup.c
@@ -0,0 +1,758 @@
+/*++
+
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ ixhwsup.c
+
+Abstract:
+
+ This module contains the IoXxx routines for the NT I/O system that
+ are hardware dependent. Were these routines not hardware dependent,
+ they would reside in the iosubs.c module.
+
+Author:
+
+ Darryl E. Havens (darrylh) 11-Apr-1990
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "halp.h"
+
+#if MCA
+#include "mca.h"
+#else
+#include "eisa.h"
+#endif
+
+
+PVOID HalpEisaControlBase;
+
+//
+// Define save area for EISA adapter objects.
+//
+
+PADAPTER_OBJECT HalpEisaAdapter[8];
+
+VOID
+HalpCopyBufferMap(
+ IN PMDL Mdl,
+ IN PTRANSLATION_ENTRY TranslationEntry,
+ IN PVOID CurrentVa,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ );
+
+
+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);
+
+ }
+
+}
+
+PVOID
+HalAllocateCommonBuffer(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN ULONG Length,
+ OUT PPHYSICAL_ADDRESS LogicalAddress,
+ IN BOOLEAN CacheEnabled
+ )
+/*++
+
+Routine Description:
+
+ This function allocates the memory for a common buffer and maps so that it
+ can be accessed by a master device and the CPU.
+
+Arguments:
+
+ AdapterObject - Supplies a pointer to the adapter object used by this
+ device.
+
+ Length - Supplies the length of the common buffer to be allocated.
+
+ LogicalAddress - Returns the logical address of the common buffer.
+
+ CacheEnable - Indicates whether the memeory is cached or not.
+
+Return Value:
+
+ Returns the virtual address of the common buffer. If the buffer cannot be
+ allocated then NULL is returned.
+
+--*/
+
+{
+
+ PVOID virtualAddress;
+ PVOID virtualAddress2;
+ PHYSICAL_ADDRESS physicalAddress;
+
+ UNREFERENCED_PARAMETER( CacheEnabled );
+
+ //
+ // Assume below 16M
+ //
+
+ physicalAddress.HighPart = 0;
+ physicalAddress.LowPart = MAXIMUM_PHYSICAL_ADDRESS-1;
+
+ //
+ // If the caller support 32bit addresses, and it's a master let
+ // it have any memory below 4G
+ //
+
+ if (AdapterObject->Dma32BitAddresses && AdapterObject->MasterDevice) {
+ physicalAddress.LowPart = 0xFFFFFFFF;
+ }
+
+ virtualAddress = MmAllocateContiguousMemory(
+ Length,
+ physicalAddress
+ );
+
+ if (virtualAddress == NULL) {
+ return(NULL);
+ }
+
+ *LogicalAddress = MmGetPhysicalAddress(virtualAddress);
+
+ if (HalpBusType != MACHINE_TYPE_ISA || AdapterObject->MasterDevice) {
+ return(virtualAddress);
+ }
+
+ //
+ // This is an ISA system the common buffer cannot cross a 64 K bountry.
+ //
+
+ if ((LogicalAddress->LowPart + Length & ~0xFFFF) ==
+ (LogicalAddress->LowPart & ~0xFFFF)) {
+
+ //
+ // This buffer is ok so return it.
+ //
+
+ return(virtualAddress);
+
+ }
+
+ //
+ // Try to allocate a buffer agian and see if this is good.
+ //
+
+ virtualAddress2 = MmAllocateContiguousMemory(
+ Length,
+ physicalAddress
+ );
+
+ //
+ // Free the first buffer.
+ //
+
+ MmFreeContiguousMemory(virtualAddress);
+
+ if (virtualAddress2 == NULL) {
+ return(NULL);
+ }
+
+ *LogicalAddress = MmGetPhysicalAddress(virtualAddress2);
+
+ if ((LogicalAddress->LowPart + Length & ~0xFFFF) ==
+ (LogicalAddress->LowPart & ~0xFFFF)) {
+
+ //
+ // This buffer is ok so return it.
+ //
+
+ return(virtualAddress2);
+
+ }
+
+ //
+ // Try our best but just could not do it. Free the buffer.
+ //
+
+ MmFreeContiguousMemory(virtualAddress2);
+
+ return(NULL);
+}
+
+BOOLEAN
+HalFlushCommonBuffer(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN ULONG Length,
+ IN PHYSICAL_ADDRESS LogicalAddress,
+ IN PVOID VirtualAddress
+ )
+/*++
+
+Routine Description:
+
+ This function is called to flush any hardware adapter buffers when the
+ driver needs to read data written by an I/O master device to a common
+ buffer.
+
+Arguments:
+
+ AdapterObject - Supplies a pointer to the adapter object used by this
+ device.
+
+ Length - Supplies the length of the common buffer. This should be the same
+ value used for the allocation of the buffer.
+
+ LogicalAddress - Supplies the logical address of the common buffer. This
+ must be the same value return by HalAllocateCommonBuffer.
+
+ VirtualAddress - Supplies the virtual address of the common buffer. This
+ must be the same value return by HalAllocateCommonBuffer.
+
+Return Value:
+
+ Returns TRUE if no errors were detected; otherwise, FALSE is return.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER( AdapterObject );
+ UNREFERENCED_PARAMETER( Length );
+ UNREFERENCED_PARAMETER( LogicalAddress );
+ UNREFERENCED_PARAMETER( VirtualAddress );
+
+ return(TRUE);
+
+}
+
+VOID
+HalFreeCommonBuffer(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN ULONG Length,
+ IN PHYSICAL_ADDRESS LogicalAddress,
+ IN PVOID VirtualAddress,
+ IN BOOLEAN CacheEnabled
+ )
+/*++
+
+Routine Description:
+
+ This function frees a common buffer and all of the resouces it uses.
+
+Arguments:
+
+ AdapterObject - Supplies a pointer to the adapter object used by this
+ device.
+
+ Length - Supplies the length of the common buffer. This should be the same
+ value used for the allocation of the buffer.
+
+ LogicalAddress - Supplies the logical address of the common buffer. This
+ must be the same value return by HalAllocateCommonBuffer.
+
+ VirtualAddress - Supplies the virtual address of the common buffer. This
+ must be the same value return by HalAllocateCommonBuffer.
+
+ CacheEnable - Indicates whether the memeory is cached or not.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER( AdapterObject );
+ UNREFERENCED_PARAMETER( Length );
+ UNREFERENCED_PARAMETER( LogicalAddress );
+ UNREFERENCED_PARAMETER( CacheEnabled );
+
+ MmFreeContiguousMemory (VirtualAddress);
+
+}
+
+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.
+ //
+
+ Irql = KfAcquireSpinLock( &MasterAdapter->SpinLock );
+
+ 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);
+
+ }
+ }
+
+ KfReleaseSpinLock( &MasterAdapter->SpinLock, Irql );
+
+ } else {
+
+ AdapterObject->MapRegisterBase = NULL;
+ AdapterObject->NumberOfMapRegisters = 0;
+
+ }
+
+ //
+ // If there were either enough map registers available or no map
+ // registers needed to be allocated, invoke the driver's execution
+ // routine now.
+ //
+
+ if (!Busy) {
+ AdapterObject->CurrentWcb = Wcb;
+ Action = Wcb->DeviceRoutine( Wcb->DeviceObject,
+ Wcb->CurrentIrp,
+ AdapterObject->MapRegisterBase,
+ Wcb->DeviceContext );
+
+ //
+ // If the execution routine would like to have the adapter
+ // deallocated, then release the adapter object.
+ //
+
+ if (Action == KeepObject) {
+
+ //
+ // This request wants to keep the channel a while so break
+ // out of the loop.
+ //
+
+ break;
+
+ }
+
+ //
+ // If the driver wants to keep the map registers then set the
+ // number allocated to 0. This keeps the deallocation routine
+ // from deallocating them.
+ //
+
+ if (Action == DeallocateObjectKeepRegisters) {
+ AdapterObject->NumberOfMapRegisters = 0;
+ }
+
+ } else {
+
+ //
+ // This request did not get the requested number of map registers so
+ // out of the loop.
+ //
+
+ break;
+ }
+ }
+}
+
+VOID
+IoFreeMapRegisters(
+ PADAPTER_OBJECT AdapterObject,
+ PVOID MapRegisterBase,
+ ULONG NumberOfMapRegisters
+ )
+/*++
+
+Routine Description:
+
+ This routine deallocates the map registers for the adapter. If there are
+ any queued adapter waiting for an attempt is made to allocate the next
+ entry.
+
+Arguments:
+
+ AdapterObject - The adapter object to where the map register should be
+ returned.
+
+ MapRegisterBase - The map register base of the registers to be deallocated.
+
+ NumberOfMapRegisters - The number of registers to be deallocated.
+
+Return Value:
+
+ None
+
+--+*/
+{
+ PADAPTER_OBJECT MasterAdapter;
+ LONG MapRegisterNumber;
+ PWAIT_CONTEXT_BLOCK Wcb;
+ PLIST_ENTRY Packet;
+ IO_ALLOCATION_ACTION Action;
+ KIRQL Irql;
+
+
+ //
+ // Begin by getting the address of the master adapter.
+ //
+
+ if (AdapterObject->MasterAdapter != NULL && MapRegisterBase != NULL) {
+
+ MasterAdapter = AdapterObject->MasterAdapter;
+
+ } else {
+
+ //
+ // There are no map registers to return.
+ //
+
+ return;
+ }
+
+ //
+ // Strip no scatter/gather flag.
+ //
+
+ MapRegisterBase = (PVOID) ((ULONG) MapRegisterBase & ~NO_SCATTER_GATHER);
+
+ MapRegisterNumber = (PTRANSLATION_ENTRY) MapRegisterBase -
+ (PTRANSLATION_ENTRY) MasterAdapter->MapRegisterBase;
+
+ //
+ // Acquire the master adapter spinlock which locks the adapter queue and the
+ // bit map for the map registers.
+ //
+
+ Irql = KfAcquireSpinLock(&MasterAdapter->SpinLock);
+
+ //
+ // 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;
+
+ }
+
+ KfReleaseSpinLock( &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.
+ //
+
+ Irql = KfAcquireSpinLock( &MasterAdapter->SpinLock );
+
+ RtlClearBits( MasterAdapter->MapRegisters,
+ MapRegisterNumber,
+ AdapterObject->NumberOfMapRegisters
+ );
+
+ AdapterObject->NumberOfMapRegisters = 0;
+
+ KfReleaseSpinLock( &MasterAdapter->SpinLock, Irql );
+ }
+
+ IoFreeAdapterChannel( AdapterObject );
+ }
+
+ Irql = KfAcquireSpinLock( &MasterAdapter->SpinLock );
+
+ }
+
+ KfReleaseSpinLock( &MasterAdapter->SpinLock, Irql );
+}
diff --git a/private/ntos/nthals/halx86/i386/ixidle.asm b/private/ntos/nthals/halx86/i386/ixidle.asm
new file mode 100644
index 000000000..8dea29cd9
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixidle.asm
@@ -0,0 +1,88 @@
+ title "Hal Processor Idle"
+;++
+;
+;Copyright (c) 1991 Microsoft Corporation
+;
+;Module Name:
+;
+; ixidle.asm
+;
+;Abstract:
+;
+;
+;Author:
+;
+;
+;Revision History:
+;
+;--
+
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+include i386\kimacro.inc
+include mac386.inc
+ .list
+
+_TEXT$01 SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+ page ,132
+ subttl "HalProcessorIdle"
+;++
+;
+; VOID
+; HalProcessorIdle(
+; VOID
+; )
+;
+; Routine Description:
+;
+; This function is called when the current processor is idle.
+;
+; This function is called with interrupts disabled, and the processor
+; is idle until it receives an interrupt. The does not need to return
+; until an interrupt is received by the current processor.
+;
+; This is the lowest level of processor idle. It occurs frequently,
+; and this function (alone) should not put the processor into a
+; power savings mode which requeres large amount of time to enter & exit.
+;
+; Return Value:
+;
+;--
+
+cPublicProc _HalProcessorIdle, 0
+
+ ;
+ ; the following code sequence "sti-halt" puts the processor
+ ; into a Halted state, with interrupts enabled, without processing
+ ; an interrupt before halting. The STI instruction has a delay
+ ; slot such that it does not take effect until after the instruction
+ ; following it - this has the effect of HALTing without allowing
+ ; a possible interrupt and then enabling interrupts while HALTed.
+ ;
+
+ ;
+ ; On an MP hal we don't stop the processor, since that causes
+ ; the SNOOP to slow down as well
+ ;
+
+ sti
+
+ifdef NT_UP
+ hlt
+endif
+
+ ;
+ ; Now return to the system. If there's still no work, then it
+ ; will call us back to halt again.
+ ;
+
+ stdRET _HalProcessorIdle
+
+stdENDP _HalProcessorIdle
+
+_TEXT$01 ends
+ end
diff --git a/private/ntos/nthals/halx86/i386/ixinfo.c b/private/ntos/nthals/halx86/i386/ixinfo.c
new file mode 100644
index 000000000..d39fdcc35
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixinfo.c
@@ -0,0 +1,285 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ixinfo.c
+
+Abstract:
+
+Author:
+
+ Ken Reneris (kenr) 08-Aug-1994
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+
+#include "halp.h"
+
+#ifdef _PNP_POWER_
+HAL_CALLBACKS HalCallback;
+extern WCHAR rgzSuspendCallbackName[];
+
+VOID
+HalInitSystemPhase2 (
+ VOID
+ );
+
+VOID
+HalpLockSuspendCode (
+ IN PVOID CallbackContext,
+ IN PVOID Argument1,
+ IN PVOID Argument2
+ );
+#endif
+
+NTSTATUS
+HalpQueryInstalledBusInformation (
+ OUT PVOID Buffer,
+ IN ULONG BufferLength,
+ OUT PULONG ReturnedLength
+ );
+
+
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE,HaliQuerySystemInformation)
+#pragma alloc_text(PAGE,HaliSetSystemInformation)
+#pragma alloc_text(INIT,HalInitSystemPhase2)
+
+#ifdef _PNP_POWER_
+#pragma alloc_text(PAGE,HalpLockSuspendCode)
+#endif
+
+#endif
+
+
+VOID
+HalInitSystemPhase2 (
+ VOID
+ )
+{
+#ifdef _PNP_POWER_
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ NTSTATUS Status;
+ UNICODE_STRING unicodeString;
+ PCALLBACK_OBJECT CallbackObject;
+
+ //
+ // Create hal callbacks
+ //
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ NULL,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL
+ );
+
+
+ ExCreateCallback (&HalCallback.SetSystemInformation, &ObjectAttributes, TRUE, TRUE);
+ ExCreateCallback (&HalCallback.BusCheck, &ObjectAttributes, TRUE, TRUE);
+
+ //
+ // Connect to suspend callback to lock hal hibaration code
+ //
+
+ RtlInitUnicodeString(&unicodeString, rgzSuspendCallbackName);
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &unicodeString,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL
+ );
+
+ Status = ExCreateCallback (&CallbackObject, &ObjectAttributes, FALSE, FALSE);
+
+ if (NT_SUCCESS(Status)) {
+ ExRegisterCallback (
+ CallbackObject,
+ HalpLockSuspendCode,
+ NULL
+ );
+
+ ObDereferenceObject (CallbackObject);
+ }
+#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;
+ MCA_EXCEPTION McaException;
+ HAL_DISPLAY_BIOS_INFORMATION DisplayBiosInf;
+ } U;
+
+ BOOLEAN bUseFrameBufferCaching;
+
+ PAGED_CODE();
+
+ Status = STATUS_SUCCESS;
+ *ReturnedLength = 0;
+ Length = 0;
+
+ switch (InformationClass) {
+ case HalInstalledBusInformation:
+ Status = HalpQueryInstalledBusInformation (
+ Buffer,
+ BufferSize,
+ ReturnedLength
+ );
+ break;
+
+ case HalFrameBufferCachingInformation:
+
+ // Note - we want to return TRUE here to enable USWC in all
+ // cases except in a "Shared Memory Cluster" machine.
+ bUseFrameBufferCaching = TRUE;
+ InternalBuffer = &bUseFrameBufferCaching;
+ Length = sizeof (BOOLEAN);
+ break;
+
+
+ case HalMcaLogInformation:
+ InternalBuffer = &U.McaException;
+ Status = HalpGetMcaLog (&U.McaException, &Length);
+ break;
+
+ case HalDisplayBiosInformation:
+ InternalBuffer = &U.DisplayBiosInf;
+ Length = sizeof(U.DisplayBiosInf);
+ U.DisplayBiosInf = HalpGetDisplayBiosInformation ();
+ break;
+
+#ifdef _PNP_POWER_
+ case HalPowerInformation:
+ RtlZeroMemory (&U.PowerInf, sizeof(HAL_POWER_INFORMATION));
+
+ InternalBuffer = &U.PowerInf;
+ Length = sizeof (HAL_POWER_INFORMATION);
+ break;
+
+
+ case HalProcessorSpeedInformation:
+ RtlZeroMemory (&U.ProcessorInf, sizeof(HAL_POWER_INFORMATION));
+
+ U.ProcessorInf.MaximumProcessorSpeed = 100;
+ U.ProcessorInf.CurrentAvailableSpeed = 100;
+ U.ProcessorInf.ConfiguredSpeedLimit = 100;
+
+ InternalBuffer = &U.PowerInf;
+ Length = sizeof (HAL_PROCESSOR_SPEED_INFORMATION);
+ break;
+
+ case HalCallbackInformation:
+ InternalBuffer = &HalCallback;
+ Length = sizeof (HAL_CALLBACKS);
+ break;
+#endif
+ 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
+ )
+{
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ Status = STATUS_SUCCESS;
+
+ switch (InformationClass) {
+
+ case HalMcaRegisterDriver:
+ Status = HalpMcaRegisterDriver(
+ (PMCA_DRIVER_INFO) Buffer // Info about registering driver
+ );
+ break;
+
+ default:
+ Status = STATUS_INVALID_LEVEL;
+ break;
+ }
+
+ return Status;
+}
+
+
+
+#ifdef _PNP_POWER_
+
+VOID
+HalpLockSuspendCode (
+ IN PVOID CallbackContext,
+ IN PVOID Argument1,
+ IN PVOID Argument2
+ )
+{
+ static PVOID CodeLock;
+
+ switch ((ULONG) Argument1) {
+ case 0:
+ //
+ // Lock code down which might be needed to perform a suspend
+ //
+
+ ASSERT (CodeLock == NULL);
+ CodeLock = MmLockPagableCodeSection (&HaliSuspendHibernateSystem);
+ break;
+
+ case 1:
+ //
+ // Release the code lock
+ //
+
+ MmUnlockPagableImageSection (CodeLock);
+ CodeLock = NULL;
+ break;
+ }
+}
+
+#endif
diff --git a/private/ntos/nthals/halx86/i386/ixipi.asm b/private/ntos/nthals/halx86/i386/ixipi.asm
new file mode 100644
index 000000000..3eb733e8c
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixipi.asm
@@ -0,0 +1,188 @@
+ title "Interprocessor Interrupt"
+;++
+;
+;Copyright (c) 1991 Microsoft Corporation
+;
+;Module Name:
+;
+; ixipi.asm
+;
+;Abstract:
+;
+; Provides the HAL support for Interprocessor Interrupts.
+; This is the UP version.
+;
+;Author:
+;
+; John Vert (jvert) 16-Jul-1991
+;
+;Revision History:
+;
+;--
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+include i386\kimacro.inc
+include i386\ix8259.inc
+
+
+ EXTRNP _KiCoprocessorError,0,IMPORT
+ EXTRNP Kei386EoiHelper,0,IMPORT
+ EXTRNP _HalBeginSystemInterrupt,3
+ EXTRNP _HalEndSystemInterrupt,2
+ extrn _HalpDefaultInterruptAffinity:DWORD
+ extrn _HalpActiveProcessors:DWORD
+
+ page ,132
+ subttl "Post InterProcessor Interrupt"
+INIT SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+;++
+;
+; VOID
+; HalInitializeProcessor(
+; ULONG Number
+; );
+;
+;Routine Description:
+;
+; Initialize hal pcr values for current processor (if any)
+; (called shortly after processor reaches kernel, before
+; HalInitSystem if P0)
+;
+; IPI's and KeReadir/LowerIrq's must be available once this function
+; returns. (IPI's are only used once two or more processors are
+; available)
+;
+;Arguments:
+;
+; Number - Logical processor number of calling processor
+;
+;Return Value:
+;
+; None.
+;
+;--
+cPublicProc _HalInitializeProcessor ,1
+
+;
+; Initialize PcIDR in PCR to enable slave IRQ
+;
+
+ mov fs:PcIDR, 0fffffffbh
+ mov dword ptr fs:PcStallScaleFactor, INITIAL_STALL_COUNT
+
+ mov eax, dword ptr [esp+4]
+ lock bts _HalpDefaultInterruptAffinity, eax
+ lock bts _HalpActiveProcessors, eax
+
+ stdRET _HalInitializeProcessor
+stdENDP _HalInitializeProcessor
+
+INIT ends
+
+
+_TEXT$03 SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+;++
+;
+; VOID
+; HalRequestIpi(
+; IN ULONG Mask
+; );
+;
+;Routine Description:
+;
+; Requests an interprocessor interrupt
+;
+;Arguments:
+;
+; Mask - Supplies a mask of the processors to interrupt
+;
+;Return Value:
+;
+; None.
+;
+;--
+
+cPublicProc _HalRequestIpi ,1
+
+if DBG
+ int 3
+endif
+ stdRET _HalRequestIpi
+stdENDP _HalRequestIpi
+
+
+ page ,132
+ subttl "80387 Irq13 Interrupt Handler"
+;++
+;
+; VOID
+; HalpIrq13Handler (
+; );
+;
+; Routine Description:
+;
+; When the 80387 detects an error, it raises its error line. This
+; was supposed to be routed directly to the 386 to cause a trap 16
+; (which would actually occur when the 386 encountered the next FP
+; instruction).
+;
+; However, the ISA design routes the error line to IRQ13 on the
+; slave 8259. So an interrupt will be generated whenever the 387
+; discovers an error.
+;
+; This routine handles that interrupt and passes control to the kernel
+; coprocessor error handler.
+;
+; Arguments:
+;
+; None.
+; Interrupt is disabled.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+ ENTER_DR_ASSIST Hi13_a, Hi13_t
+
+cPublicProc _HalpIrq13Handler ,0
+
+;
+; Save machine state in trap frame
+;
+
+ ENTER_INTERRUPT Hi13_a, Hi13_t ; (ebp) -> Trap frame
+
+;
+; Save previous IRQL
+;
+
+ push 13 + PRIMARY_VECTOR_BASE ; Vector
+ sub esp, 4 ; make space for OldIrql
+
+ stdCall _HalBeginSystemInterrupt, <I386_80387_IRQL,13 + PRIMARY_VECTOR_BASE,esp>
+
+ stdCall _KiCoprocessorError ; call CoprocessorError handler
+
+;
+; Clear the busy latch so that the 386 doesn't mistakenly think
+; that the 387 is still busy.
+;
+
+ xor al,al
+ out I386_80387_BUSY_PORT, al
+
+ INTERRUPT_EXIT ; will return to caller
+
+stdENDP _HalpIrq13Handler
+
+_TEXT$03 ENDS
+
+ END
diff --git a/private/ntos/nthals/halx86/i386/ixirql.asm b/private/ntos/nthals/halx86/i386/ixirql.asm
new file mode 100644
index 000000000..e18a0ce8b
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixirql.asm
@@ -0,0 +1,1297 @@
+ title "Irql Processing"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; ixirql.asm
+;
+; Abstract:
+;
+; This module implements the code necessary to raise and lower i386
+; Irql and dispatch software interrupts with the 8259 PIC.
+;
+; Author:
+;
+; Shie-Lin Tzong (shielint) 8-Jan-1990
+;
+; Environment:
+;
+; Kernel mode only.
+;
+; Revision History:
+;
+; John Vert (jvert) 27-Nov-1991
+; Moved from kernel into HAL
+;
+;--
+
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+include i386\ix8259.inc
+include i386\kimacro.inc
+include mac386.inc
+ .list
+
+
+ EXTRNP _KeBugCheck,1,IMPORT
+ EXTRNP _KiDispatchInterrupt,0,IMPORT
+
+ extrn _HalpApcInterrupt:near
+ extrn _HalpDispatchInterrupt:near
+ extrn _KiUnexpectedInterrupt:near
+ extrn _HalpBusType:DWORD
+ extrn _HalpApcInterrupt2ndEntry:NEAR
+ extrn _HalpDispatchInterrupt2ndEntry:NEAR
+ extrn HalpSpecialDismissLevelTable:dword
+ extrn HalpSpecialDismissTable:dword
+ extrn _HalpEisaELCR:dword
+
+;
+; Initialization control words equates for the PICs
+;
+
+ICW1_ICW4_NEEDED equ 01H
+ICW1_CASCADE equ 00H
+ICW1_INTERVAL8 equ 00H
+ICW1_LEVEL_TRIG equ 08H
+ICW1_EDGE_TRIG equ 00H
+ICW1_ICW equ 10H
+
+ICW4_8086_MODE equ 001H
+ICW4_NORM_EOI equ 000H
+ICW4_NON_BUF_MODE equ 000H
+ICW4_SPEC_FULLY_NESTED equ 010H
+ICW4_NOT_SPEC_FULLY_NESTED equ 000H
+
+OCW2_NON_SPECIFIC_EOI equ 020H
+OCW2_SPECIFIC_EOI equ 060H
+OCW2_SET_PRIORITY equ 0c0H
+
+PIC_SLAVE_IRQ equ 2
+PIC1_BASE equ 30H
+PIC2_BASE equ 38H
+
+;
+; Interrupt flag bit maks for EFLAGS
+;
+
+EFLAGS_IF equ 200H
+EFLAGS_SHIFT equ 9
+
+;
+; Hardware irq active masks
+;
+
+IRQ_ACTIVE_MASK equ 0fffffff0h
+
+_DATA SEGMENT DWORD PUBLIC 'DATA'
+
+;
+; PICsInitializationString - Master PIC initialization command string
+;
+
+ifdef MCA
+
+PICsInitializationString dw PIC1_PORT0
+
+;
+; Master PIC initialization command
+;
+
+ db ICW1_ICW + ICW1_LEVEL_TRIG + ICW1_INTERVAL8 +\
+ ICW1_CASCADE + ICW1_ICW4_NEEDED
+ db PIC1_BASE
+ db 1 SHL PIC_SLAVE_IRQ
+ db ICW4_NOT_SPEC_FULLY_NESTED + \
+ ICW4_NON_BUF_MODE + \
+ ICW4_NORM_EOI + \
+ ICW4_8086_MODE
+;
+; Slave PIC initialization command strings
+;
+
+ dw PIC2_PORT0
+ db ICW1_ICW + ICW1_LEVEL_TRIG + ICW1_INTERVAL8 +\
+ ICW1_CASCADE + ICW1_ICW4_NEEDED
+ db PIC2_BASE
+ db PIC_SLAVE_IRQ
+ db ICW4_NOT_SPEC_FULLY_NESTED + \
+ ICW4_NON_BUF_MODE + \
+ ICW4_NORM_EOI + \
+ ICW4_8086_MODE
+ dw 0 ; end of string
+
+else
+
+PICsInitializationString dw PIC1_PORT0
+
+;
+; Master PIC initialization command
+;
+
+ db ICW1_ICW + ICW1_EDGE_TRIG + ICW1_INTERVAL8 +\
+ ICW1_CASCADE + ICW1_ICW4_NEEDED
+ db PIC1_BASE
+ db 1 SHL PIC_SLAVE_IRQ
+ db ICW4_NOT_SPEC_FULLY_NESTED + \
+ ICW4_NON_BUF_MODE + \
+ ICW4_NORM_EOI + \
+ ICW4_8086_MODE
+;
+; Slave PIC initialization command strings
+;
+
+ dw PIC2_PORT0
+ db ICW1_ICW + ICW1_EDGE_TRIG + ICW1_INTERVAL8 +\
+ ICW1_CASCADE + ICW1_ICW4_NEEDED
+ db PIC2_BASE
+ db PIC_SLAVE_IRQ
+ db ICW4_NOT_SPEC_FULLY_NESTED + \
+ ICW4_NON_BUF_MODE + \
+ ICW4_NORM_EOI + \
+ ICW4_8086_MODE
+ dw 0 ; end of string
+endif
+
+ align 4
+ public KiI8259MaskTable
+KiI8259MaskTable label dword
+ dd 00000000000000000000000000000000B ; irql 0
+ dd 00000000000000000000000000000000B ; irql 1
+ dd 00000000000000000000000000000000B ; irql 2
+ dd 00000000000000000000000000000000B ; irql 3
+ dd 11111111100000000000000000000000B ; irql 4
+ dd 11111111110000000000000000000000B ; irql 5
+ dd 11111111111000000000000000000000B ; irql 6
+ dd 11111111111100000000000000000000B ; irql 7
+ dd 11111111111110000000000000000000B ; irql 8
+ dd 11111111111111000000000000000000B ; irql 9
+ dd 11111111111111100000000000000000B ; irql 10
+ dd 11111111111111110000000000000000B ; irql 11
+ dd 11111111111111111000000000000000B ; irql 12
+ dd 11111111111111111100000000000000B ; irql 13
+ dd 11111111111111111110000000000000B ; irql 14
+ dd 11111111111111111111000000000000B ; irql 15
+ dd 11111111111111111111100000000000B ; irql 16
+ dd 11111111111111111111110000000000B ; irql 17
+ dd 11111111111111111111111000000000B ; irql 18
+ dd 11111111111111111111111000000000B ; irql 19
+ dd 11111111111111111111111010000000B ; irql 20
+ dd 11111111111111111111111011000000B ; irql 21
+ dd 11111111111111111111111011100000B ; irql 22
+ dd 11111111111111111111111011110000B ; irql 23
+ dd 11111111111111111111111011111000B ; irql 24
+ dd 11111111111111111111111011111000B ; irql 25
+ dd 11111111111111111111111011111010B ; irql 26
+ dd 11111111111111111111111111111010B ; irql 27
+ dd 11111111111111111111111111111011B ; irql 28
+ dd 11111111111111111111111111111011B ; irql 29
+ dd 11111111111111111111111111111011B ; irql 30
+ dd 11111111111111111111111111111011B ; irql 31
+
+;
+; This table is used to mask all pending interrupts below a given Irql
+; out of the IRR
+;
+ align 4
+
+ public FindHigherIrqlMask
+FindHigherIrqlMask label dword
+ dd 11111111111111111111111111111110B ; irql 0
+ dd 11111111111111111111111111111100B ; irql 1 (APC)
+ dd 11111111111111111111111111111000B ; irql 2 (DISPATCH)
+ dd 11111111111111111111111111110000B ; irql 3
+ dd 00000111111111111111111111110000B ; irql 4
+ dd 00000011111111111111111111110000B ; irql 5
+ dd 00000001111111111111111111110000B ; irql 6
+ dd 00000000111111111111111111110000B ; irql 7
+ dd 00000000011111111111111111110000B ; irql 8
+ dd 00000000001111111111111111110000B ; irql 9
+ dd 00000000000111111111111111110000B ; irql 10
+ dd 00000000000011111111111111110000B ; irql 11
+ dd 00000000000001111111111111110000B ; irql 12
+ dd 00000000000000111111111111110000B ; irql 13
+ dd 00000000000000011111111111110000B ; irql 14
+ dd 00000000000000001111111111110000B ; irql 15
+ dd 00000000000000000111111111110000B ; irql 16
+ dd 00000000000000000011111111110000B ; irql 17
+ dd 00000000000000000001111111110000B ; irql 18
+ dd 00000000000000000001111111110000B ; irql 19
+ dd 00000000000000000001011111110000B ; irql 20
+ dd 00000000000000000001001111110000B ; irql 20
+ dd 00000000000000000001000111110000B ; irql 22
+ dd 00000000000000000001000011110000B ; irql 23
+ dd 00000000000000000001000001110000B ; irql 24
+ dd 00000000000000000001000000110000B ; irql 25
+ dd 00000000000000000001000000010000B ; irql 26
+ dd 00000000000000000000000000010000B ; irql 27
+ dd 00000000000000000000000000000000B ; irql 28
+ dd 00000000000000000000000000000000B ; irql 29
+ dd 00000000000000000000000000000000B ; irql 30
+ dd 00000000000000000000000000000000B ; irql 31
+
+ align 4
+;
+; The following tables define the addresses of software interrupt routers
+;
+
+;
+; Use this table if there is NO machine state frame on stack already
+;
+
+ public SWInterruptHandlerTable
+SWInterruptHandlerTable label dword
+ dd offset FLAT:_KiUnexpectedInterrupt ; irql 0
+ dd offset FLAT:_HalpApcInterrupt ; irql 1
+ dd offset FLAT:_HalpDispatchInterrupt2 ; irql 2
+ dd offset FLAT:_KiUnexpectedInterrupt ; irql 3
+ dd offset FLAT:HalpHardwareInterrupt00 ; 8259 irq#0
+ dd offset FLAT:HalpHardwareInterrupt01 ; 8259 irq#1
+ dd offset FLAT:HalpHardwareInterrupt02 ; 8259 irq#2
+ dd offset FLAT:HalpHardwareInterrupt03 ; 8259 irq#3
+ dd offset FLAT:HalpHardwareInterrupt04 ; 8259 irq#4
+ dd offset FLAT:HalpHardwareInterrupt05 ; 8259 irq#5
+ dd offset FLAT:HalpHardwareInterrupt06 ; 8259 irq#6
+ dd offset FLAT:HalpHardwareInterrupt07 ; 8259 irq#7
+ dd offset FLAT:HalpHardwareInterrupt08 ; 8259 irq#8
+ dd offset FLAT:HalpHardwareInterrupt09 ; 8259 irq#9
+ dd offset FLAT:HalpHardwareInterrupt10 ; 8259 irq#10
+ dd offset FLAT:HalpHardwareInterrupt11 ; 8259 irq#11
+ dd offset FLAT:HalpHardwareInterrupt12 ; 8259 irq#12
+ dd offset FLAT:HalpHardwareInterrupt13 ; 8259 irq#13
+ dd offset FLAT:HalpHardwareInterrupt14 ; 8259 irq#14
+ dd offset FLAT:HalpHardwareInterrupt15 ; 8259 irq#15
+
+;
+; Use this table if there is already a machine state frame on stack
+;
+
+ public SWInterruptHandlerTable2
+SWInterruptHandlerTable2 label dword
+ dd offset FLAT:_KiUnexpectedInterrupt ; irql 0
+ dd offset FLAT:_HalpApcInterrupt2ndEntry ; irql 1
+ dd offset FLAT:_HalpDispatchInterrupt2ndEntry ; irql 2
+
+;
+; The following table picks up the highest pending software irq level
+; from software irr
+;
+
+ public SWInterruptLookUpTable
+SWInterruptLookUpTable label byte
+ db 0 ; SWIRR=0, so highest pending SW irql= 0
+ db 0 ; SWIRR=1, so highest pending SW irql= 0
+ db 1 ; SWIRR=2, so highest pending SW irql= 1
+ db 1 ; SWIRR=3, so highest pending SW irql= 1
+ db 2 ; SWIRR=4, so highest pending SW irql= 2
+ db 2 ; SWIRR=5, so highest pending SW irql= 2
+ db 2 ; SWIRR=6, so highest pending SW irql= 2
+ db 2 ; SWIRR=7, so highest pending SW irql= 2
+
+ifdef IRQL_METRICS
+
+ public HalRaiseIrqlCount
+ public HalLowerIrqlCount
+ public HalQuickLowerIrqlCount
+ public HalApcSoftwareIntCount
+ public HalDpcSoftwareIntCount
+ public HalHardwareIntCount
+ public HalPostponedIntCount
+ public Hal8259MaskCount
+
+HalRaiseIrqlCount dd 0
+HalLowerIrqlCount dd 0
+HalQuickLowerIrqlCount dd 0
+HalApcSoftwareIntCount dd 0
+HalDpcSoftwareIntCount dd 0
+HalHardwareIntCount dd 0
+HalPostponedIntCount dd 0
+Hal8259MaskCount dd 0
+
+endif
+_DATA ENDS
+
+ page ,132
+ subttl "Raise Irql"
+
+_TEXT$01 SEGMENT PARA PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING
+;++
+;
+; KIRQL
+; KfRaiseIrql (
+; IN KIRQL NewIrql,
+; )
+;
+; Routine Description:
+;
+; This routine is used to raise IRQL to the specified value.
+; Also, a mask will be used to mask off all the lower lever 8259
+; interrupts.
+;
+; Arguments:
+;
+; (cl) = NewIrql - the new irql to be raised to
+;
+; Return Value:
+;
+; OldIrql - the addr of a variable which old irql should be stored
+;
+;--
+
+cPublicFastCall KfRaiseIrql,1
+cPublicFpo 0, 0
+
+ xor eax, eax ; Eliminate partial stall on return to caller
+ mov al, PCR[PcIrql] ; (al) = Old Irql
+ mov PCR[PcIrql], cl ; set new irql
+
+ifdef IRQL_METRICS
+ inc HalRaiseIrqlCount
+endif
+
+if DBG
+ cmp al, cl ; old > new?
+ ja short Kri99 ; yes, go bugcheck
+
+ fstRET KfRaiseIrql
+
+cPublicFpo 2, 2
+Kri99:
+ movzx eax, al
+ movzx ecx, cl
+ push ecx ; put new irql where we can find it
+ push eax ; put old irql where we can find it
+ mov byte ptr PCR[PcIrql],0 ; avoid recursive error
+ stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return
+endif
+ fstRET KfRaiseIrql
+
+fstENDP KfRaiseIrql
+
+;++
+;
+; KIRQL
+; KeRaiseIrqlToDpcLevel (
+; )
+;
+; Routine Description:
+;
+; This routine is used to raise IRQL to DPC level.
+;
+; Arguments:
+;
+; Return Value:
+;
+; OldIrql - the addr of a variable which old irql should be stored
+;
+;--
+
+cPublicProc _KeRaiseIrqlToDpcLevel,0
+cPublicFpo 0, 0
+
+ xor eax, eax ; Eliminate partial stall
+ mov al, PCR[PcIrql] ; (al) = Old Irql
+ mov byte ptr PCR[PcIrql], DISPATCH_LEVEL ; set new irql
+
+ifdef IRQL_METRICS
+ inc HalRaiseIrqlCount
+endif
+if DBG
+ cmp al, DISPATCH_LEVEL ; old > new?
+ ja short Krid99 ; yes, go bugcheck
+endif
+
+ stdRET _KeRaiseIrqlToDpcLevel
+
+if DBG
+cPublicFpo 0,1
+Krid99: movzx eax, al
+ push eax ; put old irql where we can find it
+ stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return
+ stdRET _KeRaiseIrqlToDpcLevel
+endif
+
+stdENDP _KeRaiseIrqlToDpcLevel
+
+
+;++
+;
+; KIRQL
+; KeRaiseIrqlToSynchLevel (
+; )
+;
+; Routine Description:
+;
+; This routine is used to raise IRQL to SYNC level.
+;
+; Arguments:
+;
+; Return Value:
+;
+; OldIrql - the addr of a variable which old irql should be stored
+;
+;--
+
+cPublicProc _KeRaiseIrqlToSynchLevel,0
+cPublicFpo 0, 0
+
+ xor eax, eax ; Eliminate partial stall
+ mov al, PCR[PcIrql] ; (al) = Old Irql
+ mov byte ptr PCR[PcIrql], SYNCH_LEVEL ; set new irql
+
+ifdef IRQL_METRICS
+ inc HalRaiseIrqlCount
+endif
+if DBG
+ cmp al, SYNCH_LEVEL ; old > new?
+ ja short Kris99 ; yes, go bugcheck
+endif
+
+ stdRET _KeRaiseIrqlToSynchLevel
+
+if DBG
+cPublicFpo 0,1
+Kris99: movzx eax, al
+ push eax ; put old irql where we can find it
+ stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return
+ stdRET _KeRaiseIrqlToSynchLevel
+endif
+
+stdENDP _KeRaiseIrqlToSynchLevel
+
+;++
+;
+; VOID
+; KfLowerIrql (
+; IN KIRQL NewIrql
+; )
+;
+; Routine Description:
+;
+; This routine is used to lower IRQL to the specified value.
+; The IRQL and PIRQL will be updated accordingly. Also, this
+; routine checks to see if any software interrupt should be
+; generated. The following condition will cause software
+; interrupt to be simulated:
+; any software interrupt which has higher priority than
+; current IRQL's is pending.
+;
+; NOTE: This routine simulates software interrupt as long as
+; any pending SW interrupt level is higher than the current
+; IRQL, even when interrupts are disabled.
+;
+; Arguments:
+;
+; (cl) = NewIrql - the new irql to be set.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+cPublicFastCall KfLowerIrql,1
+cPublicFpo 0, 0
+ and ecx, 0ffh
+
+ifdef IRQL_METRICS
+ inc HalLowerIrqlCount
+endif
+
+if DBG
+ cmp cl,PCR[PcIrql] ; Make sure we are not lowering to
+ ja KliBug ; ABOVE current level
+endif
+ pushfd
+ cli
+ mov PCR[PcIrql], ecx
+ mov edx, PCR[PcIRR]
+ and edx, FindHigherIrqlMask[ecx*4] ; (edx) is the bitmask of
+ ; pending interrupts we need to
+ ; dispatch now.
+ jnz short Kli10 ; go dispatch pending interrupts
+
+;
+; no interrupts pending, return quickly.
+;
+
+ popfd
+
+ifdef IRQL_METRICS
+ inc HalQuickLowerIrqlCount
+endif
+ fstRET KfLowerIrql
+
+cPublicFpo 1, 1
+align 4
+Kli10:
+
+;
+; If there is a pending hardware interrupt, then the PICs have been
+; masked to reflect the actual Irql.
+;
+
+ bsr ecx, edx ; (ecx) = Pending irq level
+ cmp ecx, DISPATCH_LEVEL
+ ja short Kli40
+
+ call SWInterruptHandlerTable[ecx*4] ; Dispatch the pending int.
+ popfd
+
+cPublicFpo 1, 0
+ fstRET KfLowerIrql
+
+Kli40:
+;
+; Clear all the interrupt masks
+;
+
+ mov eax, PCR[PcIDR]
+ SET_8259_MASK
+
+ mov edx, 1
+ shl edx, cl
+ xor PCR[PcIRR], edx ; clear bit in IRR
+ call SWInterruptHandlerTable[ecx*4] ; Dispatch the pending int.
+ popfd
+
+cPublicFpo 1, 0
+ fstRET KfLowerIrql
+
+if DBG
+cPublicFpo 1, 2
+KliBug:
+ push ecx ; new irql for debugging
+ push PCR[PcIrql] ; old irql for debugging
+ mov byte ptr PCR[PcIrql],HIGH_LEVEL ; avoid recursive error
+ stdCall _KeBugCheck, <IRQL_NOT_LESS_OR_EQUAL> ; never return
+endif
+
+fstENDP KfLowerIrql
+
+;++
+;
+; VOID
+; HalEndSystemInterrupt
+; IN KIRQL NewIrql,
+; IN ULONG Vector
+; )
+;
+; Routine Description:
+;
+; This routine is used to lower IRQL to the specified value.
+; The IRQL and PIRQL will be updated accordingly. Also, this
+; routine checks to see if any software interrupt should be
+; generated. The following condition will cause software
+; interrupt to be simulated:
+; any software interrupt which has higher priority than
+; current IRQL's is pending.
+;
+; NOTE: This routine simulates software interrupt as long as
+; any pending SW interrupt level is higher than the current
+; IRQL, even when interrupts are disabled.
+;
+; Arguments:
+;
+; NewIrql - the new irql to be set.
+;
+; Vector - Vector number of the interrupt
+;
+; Note that esp+12 is the beginning of interrupt/trap frame and upon
+; entering to this routine the interrupts are off.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+HeiNewIrql equ [esp + 4]
+
+cPublicProc _HalEndSystemInterrupt ,2
+cPublicFpo 2, 0
+
+ xor ecx, ecx
+ mov cl, byte ptr HeiNewIrql ; get new irql value
+
+ifdef IRQL_METRICS
+ inc HalLowerIrqlCount
+endif
+
+ mov edx, PCR[PcIRR]
+ and edx, FindHigherIrqlMask[ecx*4] ; (edx) is the bitmask of
+ ; pending interrupts we need to
+ ; dispatch now.
+ mov PCR[PcIrql], ecx
+ jnz short Hei10 ; go dispatch pending interrupts
+
+;
+; no interrupts pending, return quickly.
+;
+
+
+ifdef IRQL_METRICS
+ inc HalQuickLowerIrqlCount
+endif
+ stdRET _HalEndSystemInterrupt
+
+align 4
+Hei10:
+
+;
+; If there is any delayed hardware interrupt being serviced, we leave
+; the interrupt masked and simply return.
+;
+
+ test PCR[PcIrrActive], IRQ_ACTIVE_MASK
+ jnz short Hei50
+
+ bsr ecx, edx ; (eax) = Pending irq level
+ cmp ecx, DISPATCH_LEVEL
+ jle short Hei40
+
+;
+; Clear all the interrupt masks
+;
+
+align 4
+Hei15:
+ mov eax, PCR[PcIDR]
+ SET_8259_MASK
+;
+; The pending interrupt is a hardware interrupt. To prevent the delayed
+; interrupts from overflowing stack, we check if the pending level is already
+; active. If yes, we simply return and let the higher level EndSystemInterrupt
+; handle it.
+;
+; (ecx) = pending vector
+;
+
+ mov edx, 1
+ shl edx, cl
+ test PCR[PcIrrActive], edx ; if the pending int is being
+ ; processed, just return.
+ jne short Hei50
+ or PCR[PcIrrActive], edx ; Set Active bit
+ xor PCR[PcIRR], edx ; clear bit in IRR
+ call SWInterruptHandlerTable[ecx*4] ; Note, it destroys eax
+ xor PCR[PcIrrActive], edx ; Clear bit in ActiveIrql
+ mov eax, PCR[PcIRR] ; Reload IRR
+ mov ecx, PCR[PcIrql]
+ and eax, FindHigherIrqlMask[ecx*4] ; Is any interrupt pending
+ jz short Hei50 ; (Most time it will be zero.)
+ bsr ecx, eax ; (edx) = Pending irq level
+ cmp ecx, DISPATCH_LEVEL
+ ja short Hei15
+
+Hei40:
+
+;
+; The pending interrupt is at Software Level. We simply make current
+; interrupt frame the new pending software interrupt's frame and
+; jmp to the handler routine.
+;
+
+ add esp, 12
+ jmp SWInterruptHandlerTable2[ecx*4] ; Note, it destroys eax
+
+
+Hei50:
+ stdRET _HalEndSystemInterrupt
+
+stdENDP _HalEndSystemInterrupt
+
+;++
+;
+; VOID
+; HalpEndSoftwareInterrupt
+; IN KIRQL NewIrql,
+; )
+;
+; Routine Description:
+;
+; This routine is used to lower IRQL from software interrupt
+; leverl to the specified value.
+; The IRQL and PIRQL will be updated accordingly. Also, this
+; routine checks to see if any software interrupt should be
+; generated. The following condition will cause software
+; interrupt to be simulated:
+; any software interrupt which has higher priority than
+; current IRQL's is pending.
+;
+; NOTE: This routine simulates software interrupt as long as
+; any pending SW interrupt level is higher than the current
+; IRQL, even when interrupts are disabled.
+;
+; Arguments:
+;
+; NewIrql - the new irql to be set.
+;
+; Note that esp+8 is the beginning of interrupt/trap frame and upon
+; entering to this routine the interrupts are off.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+HesNewIrql equ [esp + 4]
+
+cPublicProc _HalpEndSoftwareInterrupt ,1
+cPublicFpo 1, 0
+
+ movzx ecx, byte ptr HesNewIrql ; get new irql value
+ mov edx, PCR[PcIRR]
+ and edx, FindHigherIrqlMask[ecx*4] ; (edx) is the bitmask of
+ ; pending interrupts we need to
+ ; dispatch now.
+ mov PCR[PcIrql], ecx
+ jnz short Hes10
+
+ stdRET _HalpEndSoftwareInterrupt
+
+align 4
+Hes10:
+;
+; Check if any delayed hardware interrupt is being serviced. If yes, we
+; simply return.
+;
+
+ test PCR[PcIrrActive], IRQ_ACTIVE_MASK
+ jnz short Hes90
+
+;
+; If there is a pending hardware interrupt, then the PICs have been
+; masked to reflect the actual Irql.
+;
+
+ bsr ecx, edx ; (ecx) = Pending irq level
+ cmp ecx, DISPATCH_LEVEL
+ ja short Hes20
+
+;
+; Pending interrupt is a soft interrupt. Recycle stack frame
+;
+
+ add esp, 8
+ jmp SWInterruptHandlerTable2[ecx*4] ; Note, it destroys eax
+
+Hes20:
+;
+; Clear all the interrupt masks
+;
+
+ mov eax, PCR[PcIDR]
+ SET_8259_MASK
+
+;
+; (ecx) = Pending level
+;
+
+ mov edx, 1
+ shl edx, cl
+
+ or PCR[PcIrrActive], edx ; Set Active bit
+ xor PCR[PcIRR], edx ; clear bit in IRR
+
+ call SWInterruptHandlerTable[ecx*4] ; Dispatch the pending int.
+
+ xor PCR[PcIrrActive], edx ; Clear bit in ActiveIrql
+
+ movzx ecx, byte ptr HesNewIrql ; get new irql value
+ mov edx, PCR[PcIRR]
+ and edx, FindHigherIrqlMask[ecx*4] ; (edx) is the bitmask of
+ ; pending interrupts we need to
+ ; dispatch now.
+ jnz short Hes10
+
+Hes90: stdRET _HalpEndSoftwareInterrupt
+
+stdENDP _HalpEndSoftwareInterrupt
+
+ page ,132
+ subttl "DispatchInterrupt 2"
+
+;++
+;
+; VOID
+; HalpDispatchInterrupt2(
+; VOID
+; );
+;
+; Routine Description:
+;
+; The functional description is the same as HalpDispatchInterrupt.
+;
+; This function differs from HalpDispatchInterrupt in how it has been
+; optimized. This function is optimized for dispatching dispatch interrupts
+; for LowerIrql, ReleaseSpinLock, and RequestSoftwareInterrupt.
+;
+; Arguments:
+;
+; None
+; Interrupt is disabled
+;
+; Return Value:
+;
+; (edx) = 1 shl DISPATCH_LEVEL
+;
+; Warnings:
+;
+; Not all SW int handles this hal uses save all the registers
+; callers to SWInterruptHandler for H/W interrupts assume that
+; ONLY EAX & ECX are destroyed.
+;
+; Note: this function saves EBX since KiDispatchInterrupt uses
+; the value without preserving it.
+;--
+
+cPublicProc _HalpDispatchInterrupt2
+cPublicFpo 0, 2
+
+ xor ecx, ecx
+ and dword ptr PCR[PcIRR], not (1 shl DISPATCH_LEVEL) ; clear the pending bit in IRR
+
+ mov cl, PCR[PcIrql]
+
+ mov byte ptr PCR[PcIrql], DISPATCH_LEVEL; set new irql
+ push ecx ; Save OldIrql
+
+;
+; Now it is safe to enable interrupt to allow higher priority interrupt
+; to come in.
+;
+ sti
+
+ push ebx
+ stdCall _KiDispatchInterrupt ; Handle DispatchInterrupt
+ pop ebx
+ pop ecx ; (ecx) = OldIrql
+ mov edx, 1 shl DISPATCH_LEVEL
+
+ cli
+
+ mov eax, PCR[PcIRR]
+ mov PCR[PcIrql], ecx ; restore current irql
+
+ and eax, FindHigherIrqlMask[ecx*4] ; (eax) is the bitmask of
+ ; pending interrupts we need to
+ ; dispatch now.
+
+ jnz short diq10 ; go dispatch pending interrupts
+ stdRET _HalpDispatchInterrupt2
+
+diq10:
+;
+; If there is a pending hardware interrupt, then the PICs have been
+; masked to reflect the actual Irql.
+;
+
+ bsr ecx, eax ; (ecx) = Pending irq level
+ cmp ecx, DISPATCH_LEVEL
+ jbe short diq20
+
+;
+; Clear all the interrupt masks
+;
+
+ mov eax, PCR[PcIDR]
+ SET_8259_MASK
+
+ mov edx, 1
+ shl edx, cl
+ xor PCR[PcIRR], edx ; clear bit in IRR
+
+diq20:
+;
+; (ecx) = Pending level
+;
+
+ jmp SWInterruptHandlerTable[ecx*4] ; Dispatch the pending int.
+diq90: stdRET _HalpDispatchInterrupt2
+
+stdENDP _HalpDispatchInterrupt2
+
+ page ,132
+ subttl "Get current irql"
+
+;++
+;
+; KIRQL
+; KeGetCurrentIrql (VOID)
+;
+; Routine Description:
+;
+; This routine returns to current IRQL.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; The current IRQL.
+;
+;--
+
+cPublicProc _KeGetCurrentIrql ,0
+cPublicFpo 0, 0
+
+ movzx eax, byte ptr PCR[PcIrql] ; Current irql is in the PCR
+ stdRET _KeGetCurrentIrql
+stdENDP _KeGetCurrentIrql
+
+
+
+;++
+;
+; VOID
+; HalpDisableAllInterrupts (VOID)
+;
+; Routine Description:
+;
+; This routine is called during a system crash. The hal needs all
+; interrupts disabled.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; None - all interrupts are masked off
+;
+;--
+
+cPublicProc _HalpDisableAllInterrupts,0
+cPublicFpo 0, 0
+
+ ;
+ ; Mask interrupts off at PIC
+ ; (raising to high_level does not work on lazy irql implementation)
+ ;
+ mov eax, KiI8259MaskTable[HIGH_LEVEL*4]; get pic masks for the new irql
+ or eax, PCR[PcIDR] ; mask irqs which are disabled
+ SET_8259_MASK ; set 8259 masks
+
+ mov byte ptr PCR[PcIrql], HIGH_LEVEL ; set new irql
+
+ stdRET _HalpDisableAllInterrupts
+
+stdENDP _HalpDisableAllInterrupts
+
+ page ,132
+ subttl "Postponed Hardware Interrupt Dispatcher"
+;++
+;
+; VOID
+; HalpHardwareInterruptNN (
+; VOID
+; );
+;
+; Routine Description:
+;
+; These routines branch through the IDT to simulate the appropriate
+; hardware interrupt. They use the "INT nn" instruction to do this.
+;
+; Arguments:
+;
+; None.
+;
+; Returns:
+;
+; None.
+;
+; Environment:
+;
+; IRET frame is on the stack
+;
+;--
+cPublicProc _HalpHardwareInterruptTable, 0
+cPublicFpo 0,0
+
+ public HalpHardwareInterrupt00
+HalpHardwareInterrupt00 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 0
+ ret
+
+ public HalpHardwareInterrupt01
+HalpHardwareInterrupt01 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 1
+ ret
+
+ public HalpHardwareInterrupt02
+HalpHardwareInterrupt02 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 2
+ ret
+
+ public HalpHardwareInterrupt03
+HalpHardwareInterrupt03 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 3
+ ret
+
+ public HalpHardwareInterrupt04
+HalpHardwareInterrupt04 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 4
+ ret
+
+ public HalpHardwareInterrupt05
+HalpHardwareInterrupt05 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 5
+ ret
+
+ public HalpHardwareInterrupt06
+HalpHardwareInterrupt06 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 6
+ ret
+
+ public HalpHardwareInterrupt07
+HalpHardwareInterrupt07 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 7
+ ret
+
+ public HalpHardwareInterrupt08
+HalpHardwareInterrupt08 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 8
+ ret
+
+ public HalpHardwareInterrupt09
+HalpHardwareInterrupt09 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 9
+ ret
+
+ public HalpHardwareInterrupt10
+HalpHardwareInterrupt10 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 10
+ ret
+
+ public HalpHardwareInterrupt11
+HalpHardwareInterrupt11 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 11
+ ret
+
+ public HalpHardwareInterrupt12
+HalpHardwareInterrupt12 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 12
+ ret
+
+ public HalpHardwareInterrupt13
+HalpHardwareInterrupt13 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 13
+ ret
+
+ public HalpHardwareInterrupt14
+HalpHardwareInterrupt14 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 14
+ ret
+
+ public HalpHardwareInterrupt15
+HalpHardwareInterrupt15 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 15
+ ret
+
+ public HalpHardwareInterruptLevel
+HalpHardwareInterruptLevel label byte
+cPublicFpo 0,0
+ xor eax, eax
+ mov al, PCR[PcIrql]
+ mov ecx, PCR[PcIRR]
+ and ecx, FindHigherIrqlMask[eax*4] ; (ecx) is the bitmask of
+ ; pending interrupts we need to
+ ; dispatch now.
+ jz short lvl_90 ; no pending ints
+
+ test PCR[PcIrrActive], IRQ_ACTIVE_MASK
+ jnz short lvl_90 ; let guy furture down the stack handle it
+
+ mov eax, ecx ; (eax) = bitmask
+ bsr ecx, eax ; (cl) = set bit
+
+ mov eax, 1
+ shl eax, cl
+ xor PCR[PcIRR], eax ; clear bit in IRR
+
+ call SWInterruptHandlerTable[ecx*4] ; Dispatch the pending int.
+align 4
+lvl_90:
+ ret
+
+stdENDP _HalpHardwareInterruptTable
+
+
+_TEXT$01 ends
+
+ page ,132
+ subttl "Interrupt Controller Chip Initialization"
+
+_TEXT SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING
+;++
+;
+; VOID
+; HalpInitializePICs (
+; )
+;
+; Routine Description:
+;
+; This routine sends the 8259 PIC initialization commands and
+; masks all the interrupts on 8259s.
+;
+; Arguments:
+;
+; None
+;
+; Return Value:
+;
+; None.
+;
+;--
+cPublicProc _HalpInitializePICs ,0
+cPublicFpo 0, 0
+
+ push esi ; save caller's esi
+ cli ; disable interrupt
+ lea esi, PICsInitializationString
+ lodsw ; (AX) = PIC port 0 address
+Hip10: movzx edx, ax
+ outsb ; output ICW1
+ IODelay
+ inc edx ; (DX) = PIC port 1 address
+ outsb ; output ICW2
+ IODelay
+ outsb ; output ICW3
+ IODelay
+ outsb ; output ICW4
+ IODelay
+ mov al, 0FFH ; mask all 8259 irqs
+ out dx,al ; write mask to PIC
+ lodsw
+ cmp ax, 0 ; end of init string?
+ jne short Hip10 ; go init next PIC
+
+;
+; Read EISA defined ELCR. If it looks good save it away.
+; If a PCI interrupts is later connected, the vector will
+; be assumed level if it's in the ELCR.
+;
+ mov edx, 4d1h ; Eisa Edge/Level port
+ in al, dx ; get e/l irq 8-f
+ mov ah, al
+ dec edx
+ in al, dx ; get e/l irq 0-7
+ and eax, 0def8h ; clear reserved bits
+ cmp eax, 0def8h ; all set?
+ je short Hip50 ; Yes, register not implemented
+
+ mov _HalpEisaELCR, eax ; Save possible ELCR settings
+
+
+;
+; If this is an EISA machine, mark all interrupts in the EISA ELCR
+; as level interrupts
+;
+ cmp _HalpBusType, MACHINE_TYPE_EISA
+ jne short Hip50
+
+;
+; Verify this isn't an OPTI chipset machine which claims to be
+; EISA, but neglects to follow the EISA spec...
+;
+
+ mov edx, 0481h ; DmaPageHighPort.Channel2
+ mov al, 055h
+ out dx, al ; out to Eisa DMA register
+ in al, dx ; read it back
+ cmp al, 055h ; if it doesn't stick, then machine
+ jne short Hip50 ; isn't support all eisa registers
+
+;
+; Ok - loop and mark all EISA level interrupts
+;
+
+ mov eax, _HalpEisaELCR
+ xor ecx, ecx ; start at irq 0
+Hip30:
+ test eax, 1 ; is level bit set?
+ jz short Hip40 ; no, go to next
+
+;
+; Found a level sensitive interrupt:
+; Set the SWInterruptHandler for the irql to be a NOP.
+; Set the SpecialDismiss entry for the irq to be the level version
+;
+ mov SWInterruptHandlerTable+4*4[ecx], offset HalpHardwareInterruptLevel
+
+ mov edx, HalpSpecialDismissLevelTable[ecx]
+ mov HalpSpecialDismissTable[ecx], edx
+
+Hip40:
+ add ecx, 4 ; next vector
+ shr eax, 1 ; shift bits down
+ jnz short Hip30 ; more set bits, then loop
+
+
+Hip50:
+ pop esi ; restore caller's esi
+ sti ; enable interrupt
+ stdRET _HalpInitializePICs
+stdENDP _HalpInitializePICs
+
+
+_TEXT ends
+
+ end
diff --git a/private/ntos/nthals/halx86/i386/ixisa.h b/private/ntos/nthals/halx86/i386/ixisa.h
new file mode 100644
index 000000000..1389962b9
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixisa.h
@@ -0,0 +1,110 @@
+/*++ BUILD Version: 0001 // Increment this if a change has global effects
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ixisa.h
+
+Abstract:
+
+ This header file defines the private Hardware Architecture Layer (HAL)
+ EISA/ISA specific interfaces, defines and structures.
+
+Author:
+
+ Jeff Havens (jhavens) 20-Jun-91
+
+Revision History:
+
+--*/
+
+#ifndef _IXISA_
+#define _IXISA_
+
+
+//
+// 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 IgnoreCount;
+ BOOLEAN Dma32BitAddresses;
+} ADAPTER_OBJECT;
+
+#endif // _IXISA_
diff --git a/private/ntos/nthals/halx86/i386/ixisabus.c b/private/ntos/nthals/halx86/i386/ixisabus.c
new file mode 100644
index 000000000..57d9348f1
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixisabus.c
@@ -0,0 +1,640 @@
+/*++
+
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ ixisabus.c
+
+Abstract:
+
+Author:
+
+Environment:
+
+Revision History:
+
+
+--*/
+
+#include "halp.h"
+
+ULONG
+HalpGetEisaInterruptVector(
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN ULONG BusInterruptLevel,
+ IN ULONG BusInterruptVector,
+ OUT PKIRQL Irql,
+ OUT PKAFFINITY Affinity
+ );
+
+BOOLEAN
+HalpTranslateIsaBusAddress (
+ IN PVOID BusHandler,
+ IN PVOID RootHandler,
+ IN PHYSICAL_ADDRESS BusAddress,
+ IN OUT PULONG AddressSpace,
+ OUT PPHYSICAL_ADDRESS TranslatedAddress
+ );
+
+BOOLEAN
+HalpTranslateEisaBusAddress (
+ IN PVOID BusHandler,
+ IN PVOID RootHandler,
+ IN PHYSICAL_ADDRESS BusAddress,
+ IN OUT PULONG AddressSpace,
+ OUT PPHYSICAL_ADDRESS TranslatedAddress
+ );
+
+BOOLEAN
+HalpTranslateSystemBusAddress (
+ IN PVOID BusHandler,
+ IN PVOID RootHandler,
+ IN PHYSICAL_ADDRESS BusAddress,
+ IN OUT PULONG AddressSpace,
+ OUT PPHYSICAL_ADDRESS TranslatedAddress
+ );
+
+NTSTATUS
+HalpAdjustEisaResourceList (
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList
+ );
+
+HalpGetEisaData (
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE,HalpGetEisaInterruptVector)
+#pragma alloc_text(PAGE,HalpAdjustEisaResourceList)
+#pragma alloc_text(PAGE,HalpGetEisaData)
+#endif
+
+
+ULONG
+HalpGetEisaInterruptVector(
+ 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.
+
+--*/
+{
+ UNREFERENCED_PARAMETER( BusInterruptVector );
+
+ //
+ // On standard PCs, IRQ 2 is the cascaded interrupt, and it really shows
+ // up on IRQ 9.
+ //
+ if (BusInterruptLevel == 2) {
+ BusInterruptLevel = 9;
+ }
+
+ if (BusInterruptLevel > 15) {
+ return 0;
+ }
+
+ //
+ // Get parent's translation from here..
+ //
+ return BusHandler->ParentHandler->GetInterruptVector (
+ BusHandler->ParentHandler,
+ RootHandler,
+ BusInterruptLevel,
+ BusInterruptVector,
+ Irql,
+ Affinity
+ );
+}
+
+NTSTATUS
+HalpAdjustEisaResourceList (
+ 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
+ );
+}
+
+BOOLEAN
+HalpTranslateIsaBusAddress(
+ 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
+
+--*/
+
+{
+ BOOLEAN Status;
+
+ //
+ // Translated normally
+ //
+
+ Status = HalpTranslateSystemBusAddress (
+ BusHandler,
+ RootHandler,
+ BusAddress,
+ AddressSpace,
+ TranslatedAddress
+ );
+
+
+ //
+ // If it could not be translated, and it's memory space
+ // then we allow the translation as it would occur on it's
+ // corrisponding EISA bus. We're allowing this because
+ // many VLBus drivers are claiming to be ISA devices.
+ // (yes, they should claim to be VLBus devices, but VLBus is
+ // run by video cards and like everything else about video
+ // there's no hope of fixing it. (At least according to
+ // Andre))
+ //
+
+ if (Status == FALSE && *AddressSpace == 0) {
+ Status = HalTranslateBusAddress (
+ Eisa,
+ BusHandler->BusNumber,
+ BusAddress,
+ AddressSpace,
+ TranslatedAddress
+ );
+ }
+
+ return Status;
+}
+
+BOOLEAN
+HalpTranslateEisaBusAddress(
+ 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
+
+--*/
+
+{
+ BOOLEAN Status;
+
+ //
+ // Translated normally
+ //
+
+ Status = HalpTranslateSystemBusAddress (
+ BusHandler,
+ RootHandler,
+ BusAddress,
+ AddressSpace,
+ TranslatedAddress
+ );
+
+
+ //
+ // If it could not be translated, and it's in the 640k - 1m
+ // range then (for compatibility) try translating it on the
+ // Internal bus for
+ //
+
+ if (Status == FALSE &&
+ *AddressSpace == 0 &&
+ BusAddress.HighPart == 0 &&
+ BusAddress.LowPart >= 0xA0000 &&
+ BusAddress.LowPart < 0xFFFFF) {
+
+ Status = HalTranslateBusAddress (
+ Internal,
+ 0,
+ BusAddress,
+ AddressSpace,
+ TranslatedAddress
+ );
+ }
+
+ return Status;
+}
+
+
+HalpGetEisaData (
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ The function returns the Eisa bus data for a slot or address.
+
+Arguments:
+
+ Buffer - Supplies the space to store the data.
+
+ Length - Supplies a count in bytes of the maximum amount to return.
+
+Return Value:
+
+ Returns the amount of data stored into the buffer.
+
+--*/
+
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ OBJECT_ATTRIBUTES BusObjectAttributes;
+ PWSTR EisaPath = L"\\Registry\\Machine\\Hardware\\Description\\System\\EisaAdapter";
+ PWSTR ConfigData = L"Configuration Data";
+ ANSI_STRING TmpString;
+ ULONG BusNumber;
+ UCHAR BusString[] = "00";
+ UNICODE_STRING RootName, BusName;
+ UNICODE_STRING ConfigDataName;
+ NTSTATUS NtStatus;
+ PKEY_VALUE_FULL_INFORMATION ValueInformation;
+ PCM_FULL_RESOURCE_DESCRIPTOR Descriptor;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialResource;
+ PCM_EISA_SLOT_INFORMATION SlotInformation;
+ ULONG PartialCount;
+ ULONG TotalDataSize, SlotDataSize;
+ HANDLE EisaHandle, BusHandle;
+ ULONG BytesWritten, BytesNeeded;
+ PUCHAR KeyValueBuffer;
+ ULONG i;
+ ULONG DataLength = 0;
+ PUCHAR DataBuffer = Buffer;
+ BOOLEAN Found = FALSE;
+
+ PAGED_CODE ();
+
+
+ RtlInitUnicodeString(
+ &RootName,
+ EisaPath
+ );
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &RootName,
+ OBJ_CASE_INSENSITIVE,
+ (HANDLE)NULL,
+ NULL
+ );
+
+ //
+ // Open the EISA root
+ //
+
+ NtStatus = ZwOpenKey(
+ &EisaHandle,
+ KEY_READ,
+ &ObjectAttributes
+ );
+
+ if (!NT_SUCCESS(NtStatus)) {
+ DbgPrint("HAL: Open Status = %x\n",NtStatus);
+ return(0);
+ }
+
+ //
+ // Init bus number path
+ //
+
+ BusNumber = BusHandler->BusNumber;
+ if (BusNumber > 99) {
+ return (0);
+ }
+
+ if (BusNumber > 9) {
+ BusString[0] += (UCHAR) (BusNumber/10);
+ BusString[1] += (UCHAR) (BusNumber % 10);
+ } else {
+ BusString[0] += (UCHAR) BusNumber;
+ BusString[1] = '\0';
+ }
+
+ RtlInitAnsiString(
+ &TmpString,
+ BusString
+ );
+
+ RtlAnsiStringToUnicodeString(
+ &BusName,
+ &TmpString,
+ TRUE
+ );
+
+
+ InitializeObjectAttributes(
+ &BusObjectAttributes,
+ &BusName,
+ OBJ_CASE_INSENSITIVE,
+ (HANDLE)EisaHandle,
+ NULL
+ );
+
+ //
+ // Open the EISA root + Bus Number
+ //
+
+ NtStatus = ZwOpenKey(
+ &BusHandle,
+ KEY_READ,
+ &BusObjectAttributes
+ );
+
+ if (!NT_SUCCESS(NtStatus)) {
+ DbgPrint("HAL: Opening Bus Number: Status = %x\n",NtStatus);
+ return(0);
+ }
+
+ //
+ // opening the configuration data. This first call tells us how
+ // much memory we need to allocate
+ //
+
+ RtlInitUnicodeString(
+ &ConfigDataName,
+ ConfigData
+ );
+
+ //
+ // This should fail. We need to make this call so we can
+ // get the actual size of the buffer to allocate.
+ //
+
+ ValueInformation = (PKEY_VALUE_FULL_INFORMATION) &i;
+ NtStatus = ZwQueryValueKey(
+ BusHandle,
+ &ConfigDataName,
+ KeyValueFullInformation,
+ ValueInformation,
+ 0,
+ &BytesNeeded
+ );
+
+ KeyValueBuffer = ExAllocatePool(
+ NonPagedPool,
+ BytesNeeded
+ );
+
+ if (KeyValueBuffer == NULL) {
+#if DBG
+ DbgPrint("HAL: Cannot allocate Key Value Buffer\n");
+#endif
+ ZwClose(BusHandle);
+ return(0);
+ }
+
+ ValueInformation = (PKEY_VALUE_FULL_INFORMATION)KeyValueBuffer;
+
+ NtStatus = ZwQueryValueKey(
+ BusHandle,
+ &ConfigDataName,
+ KeyValueFullInformation,
+ ValueInformation,
+ BytesNeeded,
+ &BytesWritten
+ );
+
+
+ ZwClose(BusHandle);
+
+ if (!NT_SUCCESS(NtStatus)) {
+#if DBG
+ DbgPrint("HAL: Query Config Data: Status = %x\n",NtStatus);
+#endif
+ ExFreePool(KeyValueBuffer);
+ return(0);
+ }
+
+
+ //
+ // We get back a Full Resource Descriptor List
+ //
+
+ Descriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PUCHAR)ValueInformation +
+ ValueInformation->DataOffset);
+
+ PartialResource = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)
+ &(Descriptor->PartialResourceList.PartialDescriptors);
+ PartialCount = Descriptor->PartialResourceList.Count;
+
+ for (i = 0; i < PartialCount; i++) {
+
+ //
+ // Do each partial Resource
+ //
+
+ switch (PartialResource->Type) {
+ case CmResourceTypeNull:
+ case CmResourceTypePort:
+ case CmResourceTypeInterrupt:
+ case CmResourceTypeMemory:
+ case CmResourceTypeDma:
+
+ //
+ // We dont care about these.
+ //
+
+ PartialResource++;
+
+ break;
+
+ case CmResourceTypeDeviceSpecific:
+
+ //
+ // Bingo!
+ //
+
+ TotalDataSize = PartialResource->u.DeviceSpecificData.DataSize;
+
+ SlotInformation = (PCM_EISA_SLOT_INFORMATION)
+ ((PUCHAR)PartialResource +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
+
+ while (((LONG)TotalDataSize) > 0) {
+
+ if (SlotInformation->ReturnCode == EISA_EMPTY_SLOT) {
+
+ SlotDataSize = sizeof(CM_EISA_SLOT_INFORMATION);
+
+ } else {
+
+ SlotDataSize = sizeof(CM_EISA_SLOT_INFORMATION) +
+ SlotInformation->NumberFunctions *
+ sizeof(CM_EISA_FUNCTION_INFORMATION);
+ }
+
+ if (SlotDataSize > TotalDataSize) {
+
+ //
+ // Something is wrong again
+ //
+
+ ExFreePool(KeyValueBuffer);
+ return(0);
+
+ }
+
+ if (SlotNumber != 0) {
+
+ SlotNumber--;
+
+ SlotInformation = (PCM_EISA_SLOT_INFORMATION)
+ ((PUCHAR)SlotInformation + SlotDataSize);
+
+ TotalDataSize -= SlotDataSize;
+
+ continue;
+
+ }
+
+ //
+ // This is our slot
+ //
+
+ Found = TRUE;
+ break;
+
+ }
+
+ //
+ // End loop
+ //
+
+ i = PartialCount;
+
+ break;
+
+ default:
+
+#if DBG
+ DbgPrint("Bad Data in registry!\n");
+#endif
+
+ ExFreePool(KeyValueBuffer);
+ return(0);
+
+ }
+
+ }
+
+ if (Found) {
+ i = Length + Offset;
+ if (i > SlotDataSize) {
+ i = SlotDataSize;
+ }
+
+ DataLength = i - Offset;
+ RtlMoveMemory (Buffer, ((PUCHAR)SlotInformation + Offset), DataLength);
+ }
+
+ ExFreePool(KeyValueBuffer);
+ return DataLength;
+}
diff --git a/private/ntos/nthals/halx86/i386/ixisasup.c b/private/ntos/nthals/halx86/i386/ixisasup.c
new file mode 100644
index 000000000..cc4effc4f
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixisasup.c
@@ -0,0 +1,1980 @@
+/*++
+
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ ixhwsup.c
+
+Abstract:
+
+ This module contains the IoXxx routines for the NT I/O system that
+ are hardware dependent. Were these routines not hardware dependent,
+ they would reside in the iosubs.c module.
+
+Author:
+
+ Darryl E. Havens (darrylh) 11-Apr-1990
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "halp.h"
+#include "eisa.h"
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE,HalGetAdapter)
+#endif
+
+//
+// The HalpNewAdapter event is used to serialize allocations
+// of new adapter objects, additions to the HalpEisaAdapter
+// array, and some global values (MasterAdapterObject) and some
+// adapter fields modified by HalpGrowMapBuffers.
+// (AdapterObject->NumberOfMapRegisters is assumed not to be
+// growable while this even is held)
+//
+// Note: We don't really need our own an event object for this.
+//
+
+#define HalpNewAdapter HalpBusDatabaseEvent
+extern KEVENT HalpNewAdapter;
+
+PVOID HalpEisaControlBase;
+extern KSPIN_LOCK HalpSystemHardwareLock;
+
+//
+// Define save area for EISA adapter objects.
+//
+
+PADAPTER_OBJECT HalpEisaAdapter[8];
+
+VOID
+HalpCopyBufferMap(
+ IN PMDL Mdl,
+ IN PTRANSLATION_ENTRY TranslationEntry,
+ IN PVOID CurrentVa,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ );
+
+PHYSICAL_ADDRESS
+HalpMapTransfer(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN PMDL Mdl,
+ IN PVOID MapRegisterBase,
+ IN PVOID CurrentVa,
+ IN OUT PULONG Length,
+ IN BOOLEAN WriteToDevice
+ );
+
+VOID
+HalpMapTransferHelper(
+ IN PMDL Mdl,
+ IN PVOID CurrentVa,
+ IN ULONG TransferLength,
+ IN PULONG PageFrame,
+ IN OUT PULONG Length
+ );
+
+
+NTSTATUS
+HalAllocateAdapterChannel(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN PWAIT_CONTEXT_BLOCK Wcb,
+ IN ULONG NumberOfMapRegisters,
+ IN PDRIVER_CONTROL ExecutionRoutine
+ )
+/*++
+
+Routine Description:
+
+ This routine allocates the adapter channel specified by the adapter object.
+ This is accomplished by placing the device object of the driver that wants
+ to allocate the adapter on the adapter's queue. If the queue is already
+ "busy", then the adapter has already been allocated, so the device object
+ is simply placed onto the queue and waits until the adapter becomes free.
+
+ Once the adapter becomes free (or if it already is), then the driver's
+ execution routine is invoked.
+
+ Also, a number of map registers may be allocated to the driver by specifying
+ a non-zero value for NumberOfMapRegisters. Then the map register must be
+ allocated from the master adapter. Once there are a sufficient number of
+ map registers available, then the execution routine is called and the
+ base address of the allocated map registers in the adapter is also passed
+ to the driver's execution routine.
+
+Arguments:
+
+ AdapterObject - Pointer to the adapter control object to allocate to the
+ driver.
+
+ Wcb - Supplies a wait context block for saving the allocation parameters.
+ The DeviceObject, CurrentIrp and DeviceContext should be initalized.
+
+ NumberOfMapRegisters - The number of map registers that are to be allocated
+ from the channel, if any.
+
+ ExecutionRoutine - The address of the driver's execution routine that is
+ invoked once the adapter channel (and possibly map registers) have been
+ allocated.
+
+Return Value:
+
+ Returns STATUS_SUCESS unless too many map registers are requested.
+
+Notes:
+
+ Note that this routine MUST be invoked at DISPATCH_LEVEL or above.
+
+--*/
+{
+
+ PADAPTER_OBJECT MasterAdapter;
+ BOOLEAN Busy = FALSE;
+ IO_ALLOCATION_ACTION Action;
+ KIRQL Irql;
+ ULONG MapRegisterNumber;
+
+ //
+ // Begin by obtaining a pointer to the master adapter associated with this
+ // request.
+ //
+
+ MasterAdapter = AdapterObject->MasterAdapter;
+
+ //
+ // Initialize the device object's wait context block in case this device
+ // must wait before being able to allocate the adapter.
+ //
+
+ Wcb->DeviceRoutine = ExecutionRoutine;
+ Wcb->NumberOfMapRegisters = NumberOfMapRegisters;
+
+ //
+ // Allocate the adapter object for this particular device. If the
+ // adapter cannot be allocated because it has already been allocated
+ // to another device, then return to the caller now; otherwise,
+ // continue.
+ //
+
+ if (!KeInsertDeviceQueue( &AdapterObject->ChannelWaitQueue,
+ &Wcb->WaitQueueEntry )) {
+
+ //
+ // Save the parameters in case there are not enough map registers.
+ //
+
+ AdapterObject->NumberOfMapRegisters = NumberOfMapRegisters;
+ AdapterObject->CurrentWcb = Wcb;
+
+ //
+ // The adapter was not busy so it has been allocated. Now check
+ // to see whether this driver wishes to allocate any map registers.
+ // Ensure that this adapter has enough total map registers
+ // to satisfy the request.
+ //
+
+ if (NumberOfMapRegisters != 0 && AdapterObject->NeedsMapRegisters) {
+
+ //
+ // Lock the map register bit map and the adapter queue in the
+ // master adapter object. The channel structure offset is used as
+ // a hint for the register search.
+ //
+
+ if (NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel) {
+ AdapterObject->NumberOfMapRegisters = 0;
+ IoFreeAdapterChannel(AdapterObject);
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ Irql = KfAcquireSpinLock( &MasterAdapter->SpinLock );
+
+ MapRegisterNumber = (ULONG)-1;
+
+ if (IsListEmpty( &MasterAdapter->AdapterQueue)) {
+
+ MapRegisterNumber = RtlFindClearBitsAndSet(
+ MasterAdapter->MapRegisters,
+ NumberOfMapRegisters,
+ 0
+ );
+ }
+
+ if (MapRegisterNumber == -1) {
+
+ //
+ // There were not enough free map registers. Queue this request
+ // on the master adapter where is will wait until some registers
+ // are deallocated.
+ //
+
+ InsertTailList( &MasterAdapter->AdapterQueue,
+ &AdapterObject->AdapterQueue
+ );
+ Busy = 1;
+
+ } else {
+
+ //
+ // Calculate the map register base from the allocated map
+ // register and base of the master adapter object.
+ //
+
+ AdapterObject->MapRegisterBase = ((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);
+
+ }
+ }
+
+ KfReleaseSpinLock( &MasterAdapter->SpinLock, Irql );
+
+ } else {
+
+ AdapterObject->MapRegisterBase = NULL;
+ AdapterObject->NumberOfMapRegisters = 0;
+ }
+
+ //
+ // If there were either enough map registers available or no map
+ // registers needed to be allocated, invoke the driver's execution
+ // routine now.
+ //
+
+ if (!Busy) {
+
+ AdapterObject->CurrentWcb = Wcb;
+ Action = ExecutionRoutine( Wcb->DeviceObject,
+ Wcb->CurrentIrp,
+ AdapterObject->MapRegisterBase,
+ Wcb->DeviceContext );
+
+ //
+ // If the driver would like to have the adapter deallocated,
+ // then release the adapter object.
+ //
+
+ if (Action == DeallocateObject) {
+
+ IoFreeAdapterChannel( AdapterObject );
+
+ } else if (Action == DeallocateObjectKeepRegisters) {
+
+ //
+ // Set the NumberOfMapRegisters = 0 in the adapter object.
+ // This will keep IoFreeAdapterChannel from freeing the
+ // registers. After this it is the driver's responsiblity to
+ // keep track of the number of map registers.
+ //
+
+ AdapterObject->NumberOfMapRegisters = 0;
+ IoFreeAdapterChannel(AdapterObject);
+
+ }
+ }
+ }
+
+ return(STATUS_SUCCESS);
+
+}
+
+PVOID
+HalAllocateCrashDumpRegisters(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN PULONG NumberOfMapRegisters
+ )
+/*++
+
+Routine Description:
+
+ This routine is called during the crash dump disk driver's initialization
+ to allocate a number map registers permanently.
+
+Arguments:
+
+ AdapterObject - Pointer to the adapter control object to allocate to the
+ driver.
+ NumberOfMapRegisters - Number of map registers requested. This field
+ will be updated to reflect the actual number of registers allocated
+ when the number is less than what was requested.
+
+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;
+}
+
+PADAPTER_OBJECT
+HalGetAdapter(
+ IN PDEVICE_DESCRIPTION DeviceDescriptor,
+ OUT PULONG NumberOfMapRegisters
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the appropriate adapter object for the device defined
+ in the device description structure. This code works for Isa and Eisa
+ systems.
+
+Arguments:
+
+ DeviceDescriptor - Supplies a description of the deivce.
+
+ NumberOfMapRegisters - Returns the maximum number of map registers which
+ may be allocated by the device driver.
+
+Return Value:
+
+ A pointer to the requested adapter object or NULL if an adapter could not
+ be created.
+
+--*/
+
+{
+ PADAPTER_OBJECT adapterObject;
+ PVOID adapterBaseVa;
+ ULONG channelNumber;
+ ULONG controllerNumber;
+ DMA_EXTENDED_MODE extendedMode;
+ UCHAR adapterMode;
+ ULONG numberOfMapRegisters;
+ BOOLEAN useChannel;
+ ULONG maximumLength;
+ UCHAR DataByte;
+
+ PAGED_CODE();
+
+ //
+ // Make sure this is the correct version.
+ //
+
+ if (DeviceDescriptor->Version > DEVICE_DESCRIPTION_VERSION1) {
+ return( NULL );
+ }
+
+#if DBG
+ if (DeviceDescriptor->Version == DEVICE_DESCRIPTION_VERSION1) {
+ ASSERT (DeviceDescriptor->Reserved1 == FALSE);
+ ASSERT (DeviceDescriptor->Reserved2 == FALSE);
+ }
+#endif
+
+ //
+ // Determine if the the channel number is important. Master cards on
+ // Eisa and Mca do not use a channel number.
+ //
+
+ if (DeviceDescriptor->InterfaceType != Isa &&
+ DeviceDescriptor->Master) {
+
+ useChannel = FALSE;
+ } else {
+
+ useChannel = TRUE;
+ }
+
+ //
+ // Support for ISA local bus machines:
+ // If the driver is a Master but really does not want a channel since it
+ // is using the local bus DMA, just don't use an ISA channel.
+ //
+
+ if (DeviceDescriptor->InterfaceType == Isa &&
+ DeviceDescriptor->DmaChannel > 7) {
+
+ useChannel = FALSE;
+ }
+
+ //
+ // Determine if Eisa DMA is supported.
+ //
+
+ if (HalpBusType == MACHINE_TYPE_EISA) {
+
+ WRITE_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort.Channel2, 0x55);
+ DataByte = READ_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort.Channel2);
+
+ if (DataByte == 0x55) {
+ HalpEisaDma = TRUE;
+ }
+
+ }
+
+ //
+ // Limit the maximum length to 2 GB this is done so that the BYTES_TO_PAGES
+ // macro works correctly.
+ //
+
+ maximumLength = DeviceDescriptor->MaximumLength & 0x7fffffff;
+
+ //
+ // Channel 4 cannot be used since it is used for chaining. Return null if
+ // it is requested.
+ //
+
+ if (DeviceDescriptor->DmaChannel == 4 && useChannel) {
+ return(NULL);
+ }
+
+ //
+ // Determine the number of map registers for this device.
+ //
+
+ if (DeviceDescriptor->ScatterGather &&
+ (LessThan16Mb ||
+ DeviceDescriptor->InterfaceType == Eisa ||
+ DeviceDescriptor->InterfaceType == PCIBus) ) {
+
+ //
+ // Since the device support scatter/Gather then map registers are not
+ // required.
+ //
+
+ numberOfMapRegisters = 0;
+
+ } else {
+
+ //
+ // Determine the number of map registers required based on the maximum
+ // transfer length, up to a maximum number.
+ //
+
+ numberOfMapRegisters = BYTES_TO_PAGES(maximumLength)
+ + 1;
+ numberOfMapRegisters = numberOfMapRegisters > MAXIMUM_ISA_MAP_REGISTER ?
+ MAXIMUM_ISA_MAP_REGISTER : numberOfMapRegisters;
+
+ //
+ // Make sure there where enough registers allocated initalize to support
+ // this size relaibly. This implies there must be to chunks equal to
+ // the allocatd size. This is only a problem on Isa systems where the
+ // map buffers cannot cross 64KB boundtires.
+ //
+
+ if (!HalpEisaDma &&
+ numberOfMapRegisters > HalpMapBufferSize / (PAGE_SIZE * 2)) {
+
+ numberOfMapRegisters = (HalpMapBufferSize / (PAGE_SIZE * 2));
+ }
+
+ //
+ // If the device is not a master 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) HalpEisaControlBase)->Dma1BasePort;
+
+ } else {
+
+ controllerNumber = 2;
+ adapterBaseVa = &((PEISA_CONTROL) HalpEisaControlBase)->Dma2BasePort;
+
+ }
+
+ //
+ // Determine if a new adapter object is necessary. If so then allocate it.
+ //
+
+ if (useChannel && HalpEisaAdapter[DeviceDescriptor->DmaChannel] != NULL) {
+
+ adapterObject = HalpEisaAdapter[DeviceDescriptor->DmaChannel];
+
+ if (adapterObject->NeedsMapRegisters) {
+
+ if (numberOfMapRegisters > adapterObject->MapRegistersPerChannel) {
+
+ adapterObject->MapRegistersPerChannel = numberOfMapRegisters;
+ }
+ }
+
+ } else {
+
+ //
+ // Serialize before allocating a new adapter
+ //
+
+ KeWaitForSingleObject (
+ &HalpNewAdapter,
+ WrExecutive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+
+
+ //
+ // Determine if a new adapter object has already been allocated.
+ // If so use it, otherwise allocate a new adapter object
+ //
+
+ if (useChannel && HalpEisaAdapter[DeviceDescriptor->DmaChannel] != NULL) {
+
+ adapterObject = HalpEisaAdapter[DeviceDescriptor->DmaChannel];
+
+ if (adapterObject->NeedsMapRegisters) {
+
+ if (numberOfMapRegisters > adapterObject->MapRegistersPerChannel) {
+
+ adapterObject->MapRegistersPerChannel = numberOfMapRegisters;
+ }
+ }
+
+ } else {
+
+ //
+ // Allocate an adapter object.
+ //
+
+ adapterObject = (PADAPTER_OBJECT) HalpAllocateAdapter(
+ numberOfMapRegisters,
+ adapterBaseVa,
+ NULL
+ );
+
+ if (adapterObject == NULL) {
+ KeSetEvent (&HalpNewAdapter, 0, FALSE);
+ return(NULL);
+ }
+
+ if (useChannel) {
+
+ HalpEisaAdapter[DeviceDescriptor->DmaChannel] = adapterObject;
+
+ }
+
+ //
+ // Set the maximum number of map registers for this channel bus on
+ // the number requested and the type of device.
+ //
+
+ if (numberOfMapRegisters) {
+
+ //
+ // The speicified number of registers are actually allowed to be
+ // allocated.
+ //
+
+ adapterObject->MapRegistersPerChannel = numberOfMapRegisters;
+
+ //
+ // Increase the commitment for the map registers.
+ //
+
+ if (DeviceDescriptor->Master) {
+
+ //
+ // Master I/O devices use several sets of map registers double
+ // their commitment.
+ //
+
+ MasterAdapterObject->CommittedMapRegisters +=
+ numberOfMapRegisters * 2;
+
+ } else {
+
+ MasterAdapterObject->CommittedMapRegisters +=
+ numberOfMapRegisters;
+
+ }
+
+ //
+ // If the committed map registers is signicantly greater than the
+ // number allocated then grow the map buffer.
+ //
+
+ if (MasterAdapterObject->CommittedMapRegisters >
+ MasterAdapterObject->NumberOfMapRegisters &&
+ MasterAdapterObject->CommittedMapRegisters -
+ MasterAdapterObject->NumberOfMapRegisters >
+ MAXIMUM_ISA_MAP_REGISTER ) {
+
+ 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;
+ }
+ }
+ }
+
+ KeSetEvent (&HalpNewAdapter, 0, FALSE);
+
+ }
+
+ adapterObject->IgnoreCount = FALSE;
+ if (DeviceDescriptor->Version >= DEVICE_DESCRIPTION_VERSION1) {
+
+ //
+ // Move version 1 structure flags.
+ // IgnoreCount is used on machines where the DMA Counter
+ // is broken. (Namely PS/1 model 1000s). Setting this
+ // bit informs the hal not to rely on the DmaCount to determine
+ // how much data was DMAed.
+ //
+
+ adapterObject->IgnoreCount = DeviceDescriptor->IgnoreCount;
+ }
+
+ adapterObject->Dma32BitAddresses = DeviceDescriptor->Dma32BitAddresses;
+ adapterObject->ScatterGather = DeviceDescriptor->ScatterGather;
+ *NumberOfMapRegisters = adapterObject->MapRegistersPerChannel;
+
+ if (DeviceDescriptor->Master) {
+
+ adapterObject->MasterDevice = TRUE;
+
+ } else {
+
+ adapterObject->MasterDevice = FALSE;
+
+ }
+
+ //
+ // If the channel number is not used then we are finished. The rest of
+ // the work deals with channels.
+ //
+
+ if (!useChannel) {
+ return(adapterObject);
+ }
+
+ //
+ // Setup the pointers to all the random registers.
+ //
+
+ adapterObject->ChannelNumber = (UCHAR) channelNumber;
+
+ if (controllerNumber == 1) {
+
+ switch ((UCHAR)channelNumber) {
+
+ case 0:
+ adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel0;
+ break;
+
+ case 1:
+ adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel1;
+ break;
+
+ case 2:
+ adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel2;
+ break;
+
+ case 3:
+ adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel3;
+ break;
+ }
+
+ //
+ // Set the adapter number.
+ //
+
+ adapterObject->AdapterNumber = 1;
+
+ //
+ // Save the extended mode register address.
+ //
+
+ adapterBaseVa =
+ &((PEISA_CONTROL) HalpEisaControlBase)->Dma1ExtendedModePort;
+
+ } else {
+
+ switch (channelNumber) {
+ case 1:
+ adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel5;
+ break;
+
+ case 2:
+ adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel6;
+ break;
+
+ case 3:
+ adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel7;
+ break;
+ }
+
+ //
+ // Set the adapter number.
+ //
+
+ adapterObject->AdapterNumber = 2;
+
+ //
+ // Save the extended mode register address.
+ //
+ adapterBaseVa =
+ &((PEISA_CONTROL) HalpEisaControlBase)->Dma2ExtendedModePort;
+
+ }
+
+
+ adapterObject->Width16Bits = FALSE;
+
+ if (HalpEisaDma) {
+
+ //
+ // Initialzie the extended mode port.
+ //
+
+ *((PUCHAR) &extendedMode) = 0;
+ extendedMode.ChannelNumber = (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;
+
+ case Width32Bits:
+ extendedMode.TransferSize = BY_BYTE_32_BITS;
+ break;
+
+ default:
+ ObDereferenceObject( adapterObject );
+ return(NULL);
+
+ }
+
+ WRITE_PORT_UCHAR( adapterBaseVa, *((PUCHAR) &extendedMode));
+
+ } else if (!DeviceDescriptor->Master) {
+
+
+ switch (DeviceDescriptor->DmaWidth) {
+ case Width8Bits:
+
+ //
+ // The channel must use controller 1.
+ //
+
+ if (controllerNumber != 1) {
+ ObDereferenceObject( adapterObject );
+ return(NULL);
+ }
+
+ break;
+
+ case Width16Bits:
+
+ //
+ // The channel must use controller 2.
+ //
+
+ if (controllerNumber != 2) {
+ ObDereferenceObject( adapterObject );
+ return(NULL);
+ }
+
+ adapterObject->Width16Bits = TRUE;
+ break;
+
+ default:
+ ObDereferenceObject( adapterObject );
+ return(NULL);
+
+ }
+ }
+
+ //
+ // Initialize the adapter mode register value to the correct parameters,
+ // and save them in the adapter object.
+ //
+
+ adapterMode = 0;
+ ((PDMA_EISA_MODE) &adapterMode)->Channel = adapterObject->ChannelNumber;
+
+ if (DeviceDescriptor->Master) {
+
+ ((PDMA_EISA_MODE) &adapterMode)->RequestMode = CASCADE_REQUEST_MODE;
+
+ //
+ // Set the mode, and enable the request.
+ //
+
+ if (adapterObject->AdapterNumber == 1) {
+
+ //
+ // This request is for DMA controller 1
+ //
+
+ PDMA1_CONTROL dmaControl;
+
+ dmaControl = adapterObject->AdapterBaseVa;
+
+ WRITE_PORT_UCHAR( &dmaControl->Mode, adapterMode );
+
+ //
+ // Unmask the DMA channel.
+ //
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber)
+ );
+
+ } else {
+
+ //
+ // This request is for DMA controller 1
+ //
+
+ PDMA2_CONTROL dmaControl;
+
+ dmaControl = adapterObject->AdapterBaseVa;
+
+ WRITE_PORT_UCHAR( &dmaControl->Mode, adapterMode );
+
+ //
+ // Unmask the DMA channel.
+ //
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber)
+ );
+
+ }
+
+ } else if (DeviceDescriptor->DemandMode) {
+
+ ((PDMA_EISA_MODE) &adapterMode)->RequestMode = DEMAND_REQUEST_MODE;
+
+ } else {
+
+ ((PDMA_EISA_MODE) &adapterMode)->RequestMode = SINGLE_REQUEST_MODE;
+
+ }
+
+ if (DeviceDescriptor->AutoInitialize) {
+
+ ((PDMA_EISA_MODE) &adapterMode)->AutoInitialize = 1;
+
+ }
+
+ adapterObject->AdapterMode = adapterMode;
+
+ return(adapterObject);
+}
+
+
+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 transferLength;
+ PHYSICAL_ADDRESS returnAddress;
+ PULONG pageFrame;
+ ULONG pageOffset;
+
+ //
+ // If the adapter is a 32-bit bus master, take the fast path,
+ // otherwise call HalpMapTransfer for the slow path
+ //
+
+ if (MapRegisterBase == NULL) {
+
+ 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;
+
+ //
+ // Compute the starting address of the transfer
+ //
+ returnAddress.QuadPart = (ULONGLONG)( (*pageFrame << PAGE_SHIFT) + pageOffset);
+
+ //
+ // If the transfer is not completely contained within
+ // a page, call the helper to compute the appropriate
+ // length.
+ //
+ if (transferLength < *Length) {
+ HalpMapTransferHelper(Mdl, CurrentVa, transferLength, pageFrame, Length);
+ }
+ return(returnAddress);
+ }
+
+ return(HalpMapTransfer(AdapterObject,
+ Mdl,
+ MapRegisterBase,
+ CurrentVa,
+ Length,
+ WriteToDevice));
+
+}
+
+
+VOID
+HalpMapTransferHelper(
+ IN PMDL Mdl,
+ IN PVOID CurrentVa,
+ IN ULONG TransferLength,
+ IN PULONG PageFrame,
+ IN OUT PULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ Helper routine for bus master transfers that cross a page
+ boundary. This routine is separated out from the IoMapTransfer
+ fast path in order to minimize the total instruction path
+ length taken for the common network case where the entire
+ buffer being mapped is contained within one page.
+
+Arguments:
+
+ Mdl - Pointer to the MDL that describes the pages of memory that are
+ being read or written.
+
+ CurrentVa - Current virtual address in the buffer described by the MDL
+ that the transfer is being done to or from.
+
+ TransferLength = Supplies the current transferLength
+
+ PageFrame - Supplies a pointer to the starting page frame of the transfer
+
+ 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.
+
+Return Value:
+
+ None. *Length will be updated
+
+--*/
+
+{
+ do {
+ if (*PageFrame + 1 != *(PageFrame + 1)) {
+ break;
+ }
+ TransferLength += PAGE_SIZE;
+ PageFrame++;
+
+ } while ( TransferLength < *Length );
+
+
+ //
+ // Limit the Length to the maximum TransferLength.
+ //
+
+ if (TransferLength < *Length) {
+ *Length = TransferLength;
+ }
+}
+
+
+PHYSICAL_ADDRESS
+HalpMapTransfer(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN PMDL Mdl,
+ IN PVOID MapRegisterBase,
+ IN PVOID CurrentVa,
+ IN OUT PULONG Length,
+ IN BOOLEAN WriteToDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is invoked to set up the map registers in the DMA controller
+ to allow a transfer to or from a device.
+
+Arguments:
+
+ AdapterObject - Pointer to the adapter object representing the DMA
+ controller channel that has been allocated.
+
+ Mdl - Pointer to the MDL that describes the pages of memory that are
+ being read or written.
+
+ MapRegisterBase - The address of the base map register that has been
+ allocated to the device driver for use in mapping the transfer.
+
+ CurrentVa - Current virtual address in the buffer described by the MDL
+ that the transfer is being done to or from.
+
+ Length - Supplies the length of the transfer. This determines the
+ number of map registers that need to be written to map the transfer.
+ Returns the length of the transfer which was actually mapped.
+
+ WriteToDevice - Boolean value that indicates whether this is a write
+ to the device from memory (TRUE), or vice versa.
+
+Return Value:
+
+ Returns the logical address that should be used bus master controllers.
+
+--*/
+
+{
+ BOOLEAN useBuffer;
+ ULONG transferLength;
+ ULONG logicalAddress;
+ PHYSICAL_ADDRESS returnAddress;
+ ULONG index;
+ PULONG pageFrame;
+ PUCHAR bytePointer;
+ UCHAR adapterMode;
+ UCHAR dataByte;
+ PTRANSLATION_ENTRY translationEntry;
+ ULONG pageOffset;
+ KIRQL Irql;
+
+ 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;
+
+ //
+ // If the buffer is contigous and does not cross a 64 K bountry then
+ // just extend the buffer. The 64 K bountry restriction does not apply
+ // to Eisa systems.
+ //
+
+ if (HalpEisaDma) {
+
+ while( transferLength < *Length ){
+
+ if (*pageFrame + 1 != *(pageFrame + 1)) {
+ break;
+ }
+
+ transferLength += PAGE_SIZE;
+ pageFrame++;
+
+ }
+
+ } else {
+
+ while( transferLength < *Length ){
+
+ if (*pageFrame + 1 != *(pageFrame + 1) ||
+ (*pageFrame & ~0x0f) != (*(pageFrame + 1) & ~0x0f)) {
+ break;
+ }
+
+ transferLength += PAGE_SIZE;
+ pageFrame++;
+ }
+ }
+
+ //
+ // Limit the transferLength to the requested Length.
+ //
+
+ transferLength = transferLength > *Length ? *Length : transferLength;
+
+ ASSERT(MapRegisterBase != NULL);
+
+ //
+ // Strip no scatter/gather flag.
+ //
+
+ translationEntry = (PTRANSLATION_ENTRY) ((ULONG) MapRegisterBase & ~NO_SCATTER_GATHER);
+
+ if ((ULONG) MapRegisterBase & NO_SCATTER_GATHER
+ && transferLength < *Length) {
+
+ logicalAddress = translationEntry->PhysicalAddress + pageOffset;
+ translationEntry->Index = COPY_BUFFER;
+ index = 0;
+ transferLength = *Length;
+ useBuffer = TRUE;
+
+ } else {
+
+ //
+ // If there are map registers, then update the index to indicate
+ // how many have been used.
+ //
+
+ useBuffer = FALSE;
+ index = translationEntry->Index;
+ translationEntry->Index += ADDRESS_AND_SIZE_TO_SPAN_PAGES(
+ CurrentVa,
+ transferLength
+ );
+ }
+
+ //
+ // It must require memory to be at less than 16 MB. If the
+ // logical address is greater than 16MB then map registers must be used
+ //
+
+ if (logicalAddress+transferLength >= MAXIMUM_PHYSICAL_ADDRESS) {
+
+ logicalAddress = (translationEntry + index)->PhysicalAddress +
+ pageOffset;
+ useBuffer = TRUE;
+
+ if ((ULONG) MapRegisterBase & NO_SCATTER_GATHER) {
+
+ translationEntry->Index = COPY_BUFFER;
+ index = 0;
+
+ }
+
+ }
+
+ //
+ // Copy the data if necessary.
+ //
+
+ if (useBuffer && WriteToDevice) {
+ HalpCopyBufferMap(
+ Mdl,
+ translationEntry + index,
+ CurrentVa,
+ *Length,
+ WriteToDevice
+ );
+ }
+
+ //
+ // Return the length.
+ //
+
+ *Length = transferLength;
+
+ //
+ // We only support 32 bits, but the return is 64. Just
+ // zero extend
+ //
+
+ returnAddress.LowPart = logicalAddress;
+ returnAddress.HighPart = 0;
+
+ //
+ // If no adapter was specificed then there is no more work to do so
+ // return.
+ //
+
+ if (AdapterObject == NULL || AdapterObject->MasterDevice) {
+
+ return(returnAddress);
+ }
+
+ //
+ // Determine the mode based on the transfer direction.
+ //
+
+ adapterMode = AdapterObject->AdapterMode;
+ if (WriteToDevice) {
+ ((PDMA_EISA_MODE) &adapterMode)->TransferType = (UCHAR) WRITE_TRANSFER;
+ } else {
+ ((PDMA_EISA_MODE) &adapterMode)->TransferType = (UCHAR) READ_TRANSFER;
+
+ if (AdapterObject->IgnoreCount) {
+ //
+ // When the DMA is over there will be no way to tell how much
+ // data was transfered, so the entire transfer length will be
+ // copied. To ensure that no stale data is returned to the
+ // caller zero the buffer before hand.
+ //
+
+ RtlZeroMemory (
+ (PUCHAR) translationEntry[index].VirtualAddress + pageOffset,
+ transferLength
+ );
+ }
+ }
+
+ bytePointer = (PUCHAR) &logicalAddress;
+
+ if (AdapterObject->Width16Bits) {
+
+ //
+ // If this is a 16 bit transfer then adjust the length and the address
+ // for the 16 bit DMA mode.
+ //
+
+ transferLength >>= 1;
+
+ //
+ // In 16 bit DMA mode the low 16 bits are shifted right one and the
+ // page register value is unchanged. So save the page register value
+ // and shift the logical address then restore the page value.
+ //
+
+ dataByte = bytePointer[2];
+ logicalAddress >>= 1;
+ bytePointer[2] = dataByte;
+
+ }
+
+
+ //
+ // grab the spinlock for the system DMA controller
+ //
+
+ Irql = KfAcquireSpinLock( &AdapterObject->MasterAdapter->SpinLock );
+
+ //
+ // Determine the controller number based on the Adapter number.
+ //
+
+ if (AdapterObject->AdapterNumber == 1) {
+
+ //
+ // This request is for DMA controller 1
+ //
+
+ PDMA1_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 );
+
+ WRITE_PORT_UCHAR( &dmaControl->Mode, adapterMode );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseAddress,
+ bytePointer[0]
+ );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseAddress,
+ bytePointer[1]
+ );
+
+ WRITE_PORT_UCHAR(
+ ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageLowPort) +
+ (ULONG)AdapterObject->PagePort,
+ bytePointer[2]
+ );
+
+ if (HalpEisaDma) {
+
+ //
+ // Write the high page register with zero value. This enable a special mode
+ // which allows ties the page register and base count into a single 24 bit
+ // address register.
+ //
+
+ WRITE_PORT_UCHAR(
+ ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort) +
+ (ULONG)AdapterObject->PagePort,
+ 0
+ );
+ }
+
+ //
+ // Notify DMA chip of the length to transfer.
+ //
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount,
+ (UCHAR) ((transferLength - 1) & 0xff)
+ );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount,
+ (UCHAR) ((transferLength - 1) >> 8)
+ );
+
+
+ //
+ // Set the DMA chip to read or write mode; and unmask it.
+ //
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber)
+ );
+
+ } else {
+
+ //
+ // This request is for DMA controller 2
+ //
+
+ PDMA2_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 );
+
+ WRITE_PORT_UCHAR( &dmaControl->Mode, adapterMode );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseAddress,
+ bytePointer[0]
+ );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseAddress,
+ bytePointer[1]
+ );
+
+ WRITE_PORT_UCHAR(
+ ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageLowPort) +
+ (ULONG)AdapterObject->PagePort,
+ bytePointer[2]
+ );
+
+ if (HalpEisaDma) {
+
+ //
+ // Write the high page register with zero value. This enable a special mode
+ // which allows ties the page register and base count into a single 24 bit
+ // address register.
+ //
+
+ WRITE_PORT_UCHAR(
+ ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort) +
+ (ULONG)AdapterObject->PagePort,
+ 0
+ );
+ }
+
+ //
+ // Notify DMA chip of the length to transfer.
+ //
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount,
+ (UCHAR) ((transferLength - 1) & 0xff)
+ );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount,
+ (UCHAR) ((transferLength - 1) >> 8)
+ );
+
+
+ //
+ // Set the DMA chip to read or write mode; and unmask it.
+ //
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber)
+ );
+
+ }
+ KfReleaseSpinLock (&AdapterObject->MasterAdapter->SpinLock, Irql);
+ return(returnAddress);
+}
+
+BOOLEAN
+IoFlushAdapterBuffers(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN PMDL Mdl,
+ IN PVOID MapRegisterBase,
+ IN PVOID CurrentVa,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine flushes the DMA adapter object buffers. For the Jazz system
+ its clears the enable flag which aborts the dma.
+
+Arguments:
+
+ AdapterObject - Pointer to the adapter object representing the DMA
+ controller channel.
+
+ Mdl - A pointer to a Memory Descriptor List (MDL) that maps the locked-down
+ buffer to/from which the I/O occured.
+
+ MapRegisterBase - A pointer to the base of the map registers in the adapter
+ or DMA controller.
+
+ CurrentVa - The current virtual address in the buffer described the the Mdl
+ where the I/O operation occurred.
+
+ Length - Supplies the length of the transfer.
+
+ WriteToDevice - Supplies a BOOLEAN value that indicates the direction of
+ the data transfer was to the device.
+
+Return Value:
+
+ TRUE - No errors are detected so the transfer must succeed.
+
+--*/
+
+{
+ PTRANSLATION_ENTRY translationEntry;
+ PULONG pageFrame;
+ ULONG transferLength;
+ ULONG partialLength;
+ BOOLEAN masterDevice;
+
+ 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 && !AdapterObject->IgnoreCount) {
+ //
+ // 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;
+}
+
+ULONG
+HalReadDmaCounter(
+ IN PADAPTER_OBJECT AdapterObject
+ )
+/*++
+
+Routine Description:
+
+ This function reads the DMA counter and returns the number of bytes left
+ to be transfered.
+
+Arguments:
+
+ AdapterObject - Supplies a pointer to the adapter object to be read.
+
+Return Value:
+
+ Returns the number of bytes still be be transfered.
+
+--*/
+
+{
+ ULONG count;
+ ULONG high;
+ KIRQL Irql;
+
+ //
+ // Grab the spinlock for the system DMA controller.
+ //
+
+ Irql = KfAcquireSpinLock( &AdapterObject->MasterAdapter->SpinLock );
+
+ //
+ // Determine the controller number based on the Adapter number.
+ //
+
+ if (AdapterObject->AdapterNumber == 1) {
+
+ //
+ // This request is for DMA controller 1
+ //
+
+ PDMA1_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 );
+
+
+ //
+ // Initialize count to a value which will not match.
+ //
+
+ count = 0xFFFF00;
+
+ //
+ // Loop until the same high byte is read twice.
+ //
+
+ do {
+
+ high = count;
+
+ WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 );
+
+ //
+ // Read the current DMA count.
+ //
+
+ count = READ_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount
+ );
+
+ count |= READ_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount
+ ) << 8;
+
+ } while ((count & 0xFFFF00) != (high & 0xFFFF00));
+
+ } else {
+
+ //
+ // This request is for DMA controller 2
+ //
+
+ PDMA2_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 );
+
+ //
+ // Initialize count to a value which will not match.
+ //
+
+ count = 0xFFFF00;
+
+ //
+ // Loop until the same high byte is read twice.
+ //
+
+ do {
+
+ high = count;
+
+ WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 );
+
+ //
+ // Read the current DMA count.
+ //
+
+ count = READ_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount
+ );
+
+ count |= READ_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount
+ ) << 8;
+
+ } while ((count & 0xFFFF00) != (high & 0xFFFF00));
+
+
+ }
+
+ //
+ // Release the spinlock for the system DMA controller.
+ //
+
+ KfReleaseSpinLock( &AdapterObject->MasterAdapter->SpinLock, Irql );
+
+ //
+ // The DMA counter has a bias of one and can only be 16 bit long.
+ //
+
+ count = (count + 1) & 0xFFFF;
+
+ //
+ // If this is a 16 bit dma the multiply the count by 2.
+ //
+
+ if (AdapterObject->Width16Bits) {
+
+ count *= 2;
+
+ }
+
+ return(count);
+}
diff --git a/private/ntos/nthals/halx86/i386/ixkdcom.c b/private/ntos/nthals/halx86/i386/ixkdcom.c
new file mode 100644
index 000000000..644d3590b
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixkdcom.c
@@ -0,0 +1,684 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ixkdcom.c
+
+Abstract:
+
+ This module contains a very simply package to do com I/O on machines
+ with standard AT com-ports. It is C code derived from the debugger's
+ com code. Likely does not work on a PS/2. (Only rewrote the thing
+ into C so we wouldn't have to deal with random debugger macros.)
+
+ Procedures to init a com object, set and query baud rate, output
+ character, input character.
+
+Author:
+
+ Bryan M. Willman (bryanwi) 24-Sep-1990
+
+Revision History:
+
+ John Vert (jvert) 12-Jun-1991
+ Added ability to check for com-port's existence and hook onto the
+ highest com-port available.
+
+ John Vert (jvert) 19-Jul-1991
+ Moved into HAL
+
+--*/
+
+#include "halp.h"
+#include "ixkdcom.h"
+#define TIMEOUT_COUNT 1024 * 200
+
+UCHAR CpReadLsr (PCPPORT, UCHAR);
+
+extern BOOLEAN HalpOwnsDisplay;
+static UCHAR LastLsr, LastMsr;
+
+
+VOID
+CpInitialize (
+ PCPPORT Port,
+ PUCHAR Address,
+ ULONG Rate
+ )
+
+/*++
+
+ Routine Description:
+
+ Fill in the com port port object, set the initial baud rate,
+ turn on the hardware.
+
+ Arguments:
+
+ Port - address of port object
+
+ Address - port address of the com port
+ (CP_COM1_PORT, CP_COM2_PORT)
+
+ Rate - baud rate (CP_BD_150 ... CP_BD_19200)
+
+--*/
+
+{
+ PUCHAR hwport;
+ UCHAR mcr, ier;
+
+ Port->Address = Address;
+ Port->Baud = 0;
+
+ CpSetBaud(Port, Rate);
+
+ //
+ // Assert DTR, RTS.
+ //
+
+ hwport = Port->Address;
+ hwport += COM_MCR;
+
+ mcr = MC_DTRRTS;
+ WRITE_PORT_UCHAR(hwport, mcr);
+
+ hwport = Port->Address;
+ hwport += COM_IEN;
+
+ ier = 0;
+ WRITE_PORT_UCHAR(hwport, ier);
+
+}
+
+
+
+
+VOID
+CpSetBaud (
+ PCPPORT Port,
+ ULONG Rate
+ )
+
+/*++
+
+ Routine Description:
+
+ Set the baud rate for the port and record it in the port object.
+
+ Arguments:
+
+ Port - address of port object
+
+ Rate - baud rate (CP_BD_150 ... CP_BD_56000)
+
+--*/
+
+{
+ ULONG divisorlatch;
+ PUCHAR hwport;
+ UCHAR lcr;
+
+ //
+ // compute the divsor
+ //
+
+ divisorlatch = CLOCK_RATE / Rate;
+
+ //
+ // set the divisor latch access bit (DLAB) in the line control reg
+ //
+
+ hwport = Port->Address;
+ hwport += COM_LCR; // hwport = LCR register
+
+ lcr = READ_PORT_UCHAR(hwport);
+
+ lcr |= LC_DLAB;
+ WRITE_PORT_UCHAR(hwport, lcr);
+
+ //
+ // set the divisor latch value.
+ //
+
+ hwport = Port->Address;
+ hwport += COM_DLM; // divisor latch msb
+ WRITE_PORT_UCHAR(hwport, (UCHAR)((divisorlatch >> 8) & 0xff));
+
+ hwport--; // divisor latch lsb
+ WRITE_PORT_UCHAR(hwport, (UCHAR)(divisorlatch & 0xff));
+
+
+ //
+ // Set LCR to 3. (3 is a magic number in the original assembler)
+ //
+
+ hwport = Port->Address;
+ hwport += COM_LCR;
+ WRITE_PORT_UCHAR(hwport, 3);
+
+
+ //
+ // Remember the baud rate
+ //
+
+ Port->Baud = Rate;
+}
+
+
+
+USHORT
+CpQueryBaud (
+ PCPPORT Port
+ )
+
+/*++
+
+ Routine Description:
+
+ Return the last value baud rate was set to.
+
+ Arguments:
+
+ Port - address of cpport object which describes the hw port of interest.
+
+ Return Value:
+
+ Baud rate. 0 = none has been set.
+
+--*/
+
+{
+ return (USHORT) Port->Baud;
+}
+
+VOID
+CpSendModemString (
+ PCPPORT Port,
+ IN PUCHAR String
+ )
+/*++
+
+ Routine Description:
+
+ Sends a command string to the modem.
+ This is down in order to aid the modem in determining th
+ baud rate the local connect is at.
+
+ Arguments:
+
+ Port - Address of CPPORT
+ String - String to send to modem
+
+--*/
+{
+ static ULONG Delay;
+ TIME_FIELDS CurrentTime;
+ UCHAR i;
+ ULONG l;
+
+ if (Port->Flags & PORT_SENDINGSTRING)
+ return ;
+
+ Port->Flags |= PORT_SENDINGSTRING;
+ if (!Delay) {
+ // see how long 1 second is
+ HalQueryRealTimeClock (&CurrentTime);
+ l = CurrentTime.Second;
+ while (l == (ULONG) CurrentTime.Second) {
+ CpReadLsr(Port, 0);
+ HalQueryRealTimeClock (&CurrentTime);
+ Delay++;
+ }
+ Delay = Delay / 3;
+ }
+
+ l = Delay;
+ while (*String) {
+ HalQueryRealTimeClock (&CurrentTime);
+ i = CpReadLsr (Port, 0);
+ if (i & COM_OUTRDY) {
+ if ((--l) == 0) {
+ WRITE_PORT_UCHAR(Port->Address+COM_DAT, *String);
+ String++;
+ l = Delay;
+ }
+ }
+ if (i & COM_DATRDY)
+ READ_PORT_UCHAR(Port->Address + COM_DAT);
+ }
+ Port->Flags &= ~PORT_SENDINGSTRING;
+}
+
+UCHAR
+CpReadLsr (
+ PCPPORT Port,
+ UCHAR waiting
+ )
+
+/*++
+
+ Routine Description:
+
+ Read LSR byte from specified port. If HAL owns port & display
+ it will also cause a debug status to be kept up to date.
+
+ Handles entering & exiting modem control mode for debugger.
+
+ Arguments:
+
+ Port - Address of CPPORT
+
+ Returns:
+
+ Byte read from port
+
+--*/
+{
+ static UCHAR ringflag = 0;
+ static UCHAR diagout[3];
+ static ULONG diagmsg[3] = { 'TRP ', 'LVO ', 'MRF ' };
+ static UCHAR ModemString[] = "\n\rAT\n\r";
+ TIME_FIELDS CurrentTime;
+ UCHAR lsr, msr, i;
+ ULONG diagstr[12];
+
+ lsr = READ_PORT_UCHAR(Port->Address + COM_LSR);
+
+ if (lsr & COM_PE)
+ diagout[0] = 8; // Parity error
+
+ if (lsr & COM_OE)
+ diagout[1] = 8; // Overflow error
+
+ if (lsr & COM_FE)
+ diagout[2] = 8; // Framing error
+
+ if (lsr & waiting) {
+ LastLsr = ~COM_DATRDY | (lsr & COM_DATRDY);
+ return lsr;
+ }
+
+ msr = READ_PORT_UCHAR (Port->Address + COM_MSR);
+
+ if (Port->Flags & PORT_MODEMCONTROL) {
+ if (msr & SERIAL_MSR_DCD) {
+
+ //
+ // In modem control mode with carrier detect
+ // Reset carrier lost time
+ //
+
+ Port->Flags |= PORT_NOCDLTIME | PORT_MDM_CD;
+
+ } else {
+
+ //
+ // In modem control mode, but no carrier detect. After
+ // 60 seconds drop out of modem control mode
+ //
+
+ if (Port->Flags & PORT_NOCDLTIME) {
+ HalQueryRealTimeClock (&Port->CarrierLostTime);
+ Port->Flags &= ~PORT_NOCDLTIME;
+ ringflag = 0;
+ }
+
+ HalQueryRealTimeClock (&CurrentTime);
+ if (CurrentTime.Minute != Port->CarrierLostTime.Minute &&
+ CurrentTime.Second >= Port->CarrierLostTime.Second) {
+
+ //
+ // It's been at least 60 seconds - drop out of
+ // modem control mode until next RI
+ //
+
+ Port->Flags &= ~PORT_MODEMCONTROL;
+ CpSendModemString (Port, ModemString);
+ }
+
+ if (Port->Flags & PORT_MDM_CD) {
+
+ //
+ // We had a connection - if it's the connection has been
+ // down for a few seconds, then send a string to the modem
+ //
+
+ if (CurrentTime.Second < Port->CarrierLostTime.Second)
+ CurrentTime.Second += 60;
+
+ if (CurrentTime.Second > Port->CarrierLostTime.Second + 10) {
+ Port->Flags &= ~PORT_MDM_CD;
+ CpSendModemString (Port, ModemString);
+ }
+ }
+ }
+ }
+
+ if ((lsr == LastLsr && msr == LastMsr) || !(Port->Flags & PORT_SAVED))
+ return lsr;
+
+ ringflag |= (msr & SERIAL_MSR_RI) ? 1 : 2;
+ if (ringflag == 3) {
+
+ //
+ // The ring indicate line has toggled
+ // Use modem control from now on
+ //
+
+ ringflag = 0;
+ Port->Flags |= PORT_MODEMCONTROL | PORT_NOCDLTIME;
+ Port->Flags &= ~PORT_MDM_CD;
+
+ if (Port->Flags & PORT_DEFAULTRATE && Port->Baud != BD_9600) {
+
+ //
+ // Baud rate was never specified switch
+ // to 9600 baud as default (for modem usage).
+ //
+
+ HalDisplayString (MSG_DEBUG_9600);
+ CpSetBaud (Port, BD_9600);
+ //Port->Flags |= PORT_DISBAUD;
+ }
+ }
+
+ for (i=0; i < 3; i++) {
+ if (diagout[i]) {
+ diagout[i]--;
+ diagstr[10-i] = diagmsg[i];
+ } else {
+ diagstr[10-i] = ' ';
+ }
+ }
+
+ diagstr[7] = (LastLsr & COM_DATRDY) ? 'VCR ' : ' ';
+ diagstr[6] = (lsr & COM_OUTRDY) ? ' ' : 'DNS ';
+ diagstr[5] = (msr & 0x10) ? 'STC ' : ' ';
+ diagstr[4] = (msr & 0x20) ? 'RSD ' : ' ';
+ diagstr[3] = (msr & 0x40) ? ' IR ' : ' ';
+ diagstr[2] = (msr & 0x80) ? ' DC ' : ' ';
+ diagstr[1] = (Port->Flags & PORT_MODEMCONTROL) ? 'MDM ' : ' ';
+ diagstr[0] = ' ';
+#if 0
+ if (Port->Flags & PORT_DISBAUD) {
+ switch (Port->Baud) {
+ case BD_9600: diagstr[0] = ' 69 '; break;
+ case BD_14400: diagstr[0] = 'K41 '; break;
+ case BD_19200: diagstr[0] = 'K91 '; break;
+ case BD_56000: diagstr[0] = 'K65 '; break;
+ }
+ }
+#endif
+
+ HalpDisplayDebugStatus ((PUCHAR) diagstr, 11*4);
+ LastLsr = lsr;
+ LastMsr = msr;
+ return lsr;
+}
+
+
+
+
+VOID
+CpPutByte (
+ PCPPORT Port,
+ UCHAR Byte
+ )
+
+/*++
+
+ Routine Description:
+
+ Write a byte out to the specified com port.
+
+ Arguments:
+
+ Port - Address of CPPORT object
+
+ Byte - data to emit
+
+--*/
+
+{
+ UCHAR msr, lsr;
+
+ //
+ // If modem control, make sure DSR, CTS and CD are all set before
+ // sending any data.
+ //
+
+ while ((Port->Flags & PORT_MODEMCONTROL) &&
+ (msr = READ_PORT_UCHAR(Port->Address + COM_MSR) & MS_DSRCTSCD) != MS_DSRCTSCD) {
+
+ //
+ // If no CD, and there's a charactor ready, eat it
+ //
+
+ lsr = CpReadLsr (Port, 0);
+ if ((msr & MS_CD) == 0 && (lsr & COM_DATRDY) == COM_DATRDY) {
+ READ_PORT_UCHAR(Port->Address + COM_DAT);
+ }
+ }
+
+ //
+ // Wait for port to not be busy
+ //
+
+ while (!(CpReadLsr(Port, COM_OUTRDY) & COM_OUTRDY)) ;
+
+ //
+ // Send the byte
+ //
+
+ WRITE_PORT_UCHAR(Port->Address + COM_DAT, Byte);
+}
+
+USHORT
+CpGetByte (
+ PCPPORT Port,
+ PUCHAR Byte,
+ BOOLEAN WaitForByte
+ )
+
+/*++
+
+ Routine Description:
+
+ Fetch a byte and return it.
+
+ Arguments:
+
+ Port - address of port object that describes hw port
+
+ Byte - address of variable to hold the result
+
+ WaitForByte - flag indicates wait for byte or not.
+
+ Return Value:
+
+ CP_GET_SUCCESS if data returned.
+
+ CP_GET_NODATA if no data available, but no error.
+
+ CP_GET_ERROR if error (overrun, parity, etc.)
+
+--*/
+
+{
+ UCHAR lsr;
+ UCHAR value;
+ ULONG limitcount;
+
+ //
+ // Make sure DTR and CTS are set
+ //
+ // (What does CTS have to do with reading from a full duplex line???)
+
+
+ //
+ // Check to make sure the CPPORT we were passed has been initialized.
+ // (The only time it won't be initialized is when the kernel debugger
+ // is disabled, in which case we just return.)
+ //
+ if (Port->Address == NULL) {
+ return(CP_GET_NODATA);
+ }
+
+ limitcount = WaitForByte ? TIMEOUT_COUNT : 1;
+ while (limitcount != 0) {
+ limitcount--;
+
+ lsr = CpReadLsr(Port, COM_DATRDY);
+ if ((lsr & COM_DATRDY) == COM_DATRDY) {
+
+ //
+ // Check for errors
+ //
+ if (lsr & (COM_FE | COM_PE | COM_OE)) {
+ *Byte = 0;
+ return(CP_GET_ERROR);
+ }
+
+ //
+ // fetch the byte
+ //
+
+ value = READ_PORT_UCHAR(Port->Address + COM_DAT);
+
+ if (Port->Flags & PORT_MODEMCONTROL) {
+
+ //
+ // Using modem control. If no CD, then skip this byte.
+ //
+
+ if ((READ_PORT_UCHAR(Port->Address + COM_MSR) & MS_CD) == 0) {
+ continue;
+ }
+ }
+
+ *Byte = value & (UCHAR)0xff;
+ return CP_GET_SUCCESS;
+ }
+ }
+
+ LastLsr = 0;
+ CpReadLsr (Port, 0);
+ return CP_GET_NODATA;
+}
+
+
+
+BOOLEAN
+CpDoesPortExist(
+ IN PUCHAR Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will attempt to place the port into its
+ diagnostic mode. If it does it will twiddle a bit in
+ the modem control register. If the port exists this
+ twiddling should show up in the modem status register.
+
+ NOTE: This routine must be called before the device is
+ enabled for interrupts, this includes setting the
+ output2 bit in the modem control register.
+
+ This is blatantly stolen from TonyE's code in ntos\dd\serial\serial.c.
+
+Arguments:
+
+ Address - address of hw port.
+
+Return Value:
+
+ TRUE - Port exists. Party on.
+
+ FALSE - Port doesn't exist. Don't use it.
+
+--*/
+
+{
+ UCHAR OldModemStatus;
+ UCHAR ModemStatus;
+ BOOLEAN ReturnValue = TRUE;
+
+ //
+ // Save the old value of the modem control register.
+ //
+
+ OldModemStatus = READ_PORT_UCHAR(Address+COM_MCR);
+
+ //
+ // Set the port into diagnostic mode.
+ //
+
+ WRITE_PORT_UCHAR(
+ Address+COM_MCR,
+ SERIAL_MCR_LOOP
+ );
+
+ //
+ // Bang on it again to make sure that all the lower bits
+ // are clear.
+ //
+
+ WRITE_PORT_UCHAR(
+ Address+COM_MCR,
+ SERIAL_MCR_LOOP
+ );
+
+ //
+ // Read the modem status register. The high for bits should
+ // be clear.
+ //
+
+ ModemStatus = READ_PORT_UCHAR(Address+COM_MSR);
+
+ if (ModemStatus & (SERIAL_MSR_CTS | SERIAL_MSR_DSR |
+ SERIAL_MSR_RI | SERIAL_MSR_DCD)) {
+
+ ReturnValue = FALSE;
+ goto AllDone;
+
+ }
+
+ //
+ // So far so good. Now turn on OUT1 in the modem control register
+ // and this should turn on ring indicator in the modem status register.
+ //
+
+ WRITE_PORT_UCHAR(
+ Address+COM_MCR,
+ (SERIAL_MCR_OUT1 | SERIAL_MCR_LOOP)
+ );
+
+ ModemStatus = READ_PORT_UCHAR(Address+COM_MSR);
+
+ if (!(ModemStatus & SERIAL_MSR_RI)) {
+
+ ReturnValue = FALSE;
+ goto AllDone;
+
+ }
+
+AllDone: ;
+
+ //
+ // Put the modem control back into a clean state.
+ //
+
+ WRITE_PORT_UCHAR(
+ Address+COM_MCR,
+ OldModemStatus
+ );
+
+ return ReturnValue;
+
+}
+
diff --git a/private/ntos/nthals/halx86/i386/ixkdcom.h b/private/ntos/nthals/halx86/i386/ixkdcom.h
new file mode 100644
index 000000000..40171040a
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixkdcom.h
@@ -0,0 +1,165 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ixkdcom.h
+
+Abstract:
+
+ This module contains the header file for a very simple com port package.
+
+Author:
+
+ Bryan M. Willman (bryanwi) 24-Sep-1990
+
+Revision History:
+
+ John Vert (jvert) 19-Jul-1991
+ Moved into HAL
+--*/
+
+#define COM1_PORT 0x03f8
+#define COM2_PORT 0x02f8
+
+#define COM_DAT 0x00
+#define COM_IEN 0x01 // interrupt enable register
+#define COM_LCR 0x03 // line control registers
+#define COM_MCR 0x04 // modem control reg
+#define COM_LSR 0x05 // line status register
+#define COM_MSR 0x06 // modem status register
+#define COM_DLL 0x00 // divisor latch least sig
+#define COM_DLM 0x01 // divisor latch most sig
+
+#define COM_BI 0x10
+#define COM_FE 0x08
+#define COM_PE 0x04
+#define COM_OE 0x02
+
+#define LC_DLAB 0x80 // divisor latch access bit
+
+#define CLOCK_RATE 0x1C200 // USART clock rate
+
+#define MC_DTRRTS 0x03 // Control bits to assert DTR and RTS
+#define MS_DSRCTSCD 0xB0 // Status bits for DSR, CTS and CD
+#define MS_CD 0x80
+
+#define BD_150 150
+#define BD_300 300
+#define BD_600 600
+#define BD_1200 1200
+#define BD_2400 2400
+#define BD_4800 4800
+#define BD_9600 9600
+#define BD_14400 14400
+#define BD_19200 19200
+#define BD_56000 56000
+
+#define COM_OUTRDY 0x20
+#define COM_DATRDY 0x01
+
+
+//
+// This bit controls the loopback testing mode of the device. Basically
+// the outputs are connected to the inputs (and vice versa).
+//
+#define SERIAL_MCR_LOOP 0x10
+
+//
+// This bit is used for general purpose output.
+//
+#define SERIAL_MCR_OUT1 0x04
+
+//
+// This bit contains the (complemented) state of the clear to send
+// (CTS) line.
+//
+#define SERIAL_MSR_CTS 0x10
+
+//
+// This bit contains the (complemented) state of the data set ready
+// (DSR) line.
+//
+#define SERIAL_MSR_DSR 0x20
+
+//
+// This bit contains the (complemented) state of the ring indicator
+// (RI) line.
+//
+#define SERIAL_MSR_RI 0x40
+
+//
+// This bit contains the (complemented) state of the data carrier detect
+// (DCD) line.
+//
+#define SERIAL_MSR_DCD 0x80
+
+typedef struct _CPPORT {
+ PUCHAR Address;
+ ULONG Baud;
+ USHORT Flags;
+ TIME_FIELDS CarrierLostTime;
+// ULONG LockVar;
+// KSPIN_LOCK Lock;
+} CPPORT, *PCPPORT;
+
+#define PORT_DEFAULTRATE 0x0001 // baud rate not specified, using default
+#define PORT_MODEMCONTROL 0x0002 // using modem controls
+#define PORT_SAVED 0x0004 // port is in saved state
+#define PORT_NOCDLTIME 0x0010 // 'Carrier detect lost' time not set
+#define PORT_DISBAUD 0x0020 // Display baud rate abbrv
+#define PORT_SENDINGSTRING 0x0040 // Sending modem string (don't recurse)
+#define PORT_MDM_CD 0x0080 // CD while in modem control mode
+
+VOID
+CpInitialize (
+ PCPPORT Port,
+ PUCHAR Address,
+ ULONG Rate
+ );
+
+VOID
+CpSetBaud (
+ PCPPORT Port,
+ ULONG Rate
+ );
+
+USHORT
+CpQueryBaud (
+ PCPPORT Port
+ );
+
+VOID
+CpPutByte (
+ PCPPORT Port,
+ UCHAR Byte
+ );
+
+USHORT
+CpGetByte (
+ PCPPORT Port,
+ PUCHAR Byte,
+ BOOLEAN WaitForData
+ );
+
+VOID
+CpLockPort (
+ PCPPORT Port
+ );
+
+VOID
+CpUnlockPort (
+ PCPPORT Port
+ );
+
+VOID
+CpStallExecution (
+ VOID
+ );
+
+BOOLEAN
+CpDoesPortExist(
+ IN PUCHAR Address
+ );
+
diff --git a/private/ntos/nthals/halx86/i386/ixlock.asm b/private/ntos/nthals/halx86/i386/ixlock.asm
new file mode 100644
index 000000000..98cf9c425
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixlock.asm
@@ -0,0 +1,475 @@
+ title "Irql Processing"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; ixlock.asm
+;
+; Abstract:
+;
+; This module implements various locking functions optimized for this hal.
+;
+; Author:
+;
+; Ken Reneris (kenr) 21-April-1994
+;
+; Environment:
+;
+; Kernel mode only.
+;
+; Revision History:
+;
+;--
+
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+include i386\ix8259.inc
+include i386\kimacro.inc
+include mac386.inc
+ .list
+
+ EXTRNP _KeBugCheck,1,IMPORT
+ EXTRNP _KeSetEventBoostPriority, 2, IMPORT
+ EXTRNP _KeWaitForSingleObject,5, IMPORT
+
+ extrn FindHigherIrqlMask:DWORD
+ extrn SWInterruptHandlerTable:DWORD
+
+ EXTRNP _KeRaiseIrql,2
+ EXTRNP _KeLowerIrql,1
+
+ifdef NT_UP
+ LOCK_ADD equ add
+ LOCK_DEC equ dec
+else
+ LOCK_ADD equ lock add
+ LOCK_DEC equ lock dec
+endif
+
+ page ,132
+ subttl "AcquireSpinLock"
+
+_TEXT$01 SEGMENT PARA PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING
+
+;++
+;
+; KIRQL
+; KfAcquireSpinLock (
+; IN PKSPIN_LOCK SpinLock
+; )
+;
+; Routine Description:
+;
+; This function raises to DISPATCH_LEVEL and then acquires a the
+; kernel spin lock.
+;
+; In a UP hal spinlock serialization is accomplished by raising the
+; IRQL to DISPATCH_LEVEL. The SpinLock is not used; however, for
+; debugging purposes if the UP hal is compiled with the NT_UP flag
+; not set (ie, MP) we take the SpinLock.
+;
+; Arguments:
+;
+; (ecx) = SpinLock Supplies a pointer to an kernel spin lock.
+;
+; Return Value:
+;
+; OldIrql
+;
+;--
+
+cPublicFastCall KfAcquireSpinLock,1
+cPublicFpo 0,0
+
+ xor eax, eax ; Eliminate partial stall on return to caller
+ mov al, PCR[PcIrql] ; (al) = Old Irql
+ mov byte ptr PCR[PcIrql], DISPATCH_LEVEL ; set new irql
+
+ifndef NT_UP
+asl10: ACQUIRE_SPINLOCK ecx,<short asl20>
+endif
+
+ifdef IRQL_METRICS
+ inc HalRaiseIrqlCount
+endif
+if DBG
+ cmp al, DISPATCH_LEVEL ; old > new?
+ ja short asl99 ; yes, go bugcheck
+endif
+ fstRET KfAcquireSpinLock
+
+ifndef NT_UP
+asl20: SPIN_ON_SPINLOCK ecx,<short asl10>
+endif
+
+if DBG
+cPublicFpo 2,1
+asl99: movzx eax, al
+ push eax ; put old irql where we can find it
+ stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return
+endif
+ fstRET KfAcquireSpinLock
+fstENDP KfAcquireSpinLock
+
+;++
+;
+; KIRQL
+; KeAcquireSpinLockRaiseToSynch (
+; IN PKSPIN_LOCK SpinLock
+; )
+;
+; Routine Description:
+;
+; This function acquires the SpinLock at SYNCH_LEVEL. The function
+; is optmized for hoter locks (the lock is tested before acquired.
+; Any spin should occur at OldIrql; however, since this is a UP hal
+; we don't have the code for it)
+;
+; In a UP hal spinlock serialization is accomplished by raising the
+; IRQL to SYNCH_LEVEL. The SpinLock is not used; however, for
+; debugging purposes if the UP hal is compiled with the NT_UP flag
+; not set (ie, MP) we take the SpinLock.
+;
+; Arguments:
+;
+; (ecx) = SpinLock Supplies a pointer to an kernel spin lock.
+;
+; Return Value:
+;
+; OldIrql
+;
+;--
+
+cPublicFastCall KeAcquireSpinLockRaiseToSynch,1
+cPublicFpo 0,0
+
+ mov al, PCR[PcIrql] ; (al) = Old Irql
+ mov byte ptr PCR[PcIrql], SYNCH_LEVEL ; set new irql
+
+ifndef NT_UP
+asls10: ACQUIRE_SPINLOCK ecx,<short asls20>
+endif
+
+ifdef IRQL_METRICS
+ inc HalRaiseIrqlCount
+endif
+if DBG
+ cmp al, SYNCH_LEVEL ; old > new?
+ ja short asls99 ; yes, go bugcheck
+endif
+ fstRET KeAcquireSpinLockRaiseToSynch
+
+ifndef NT_UP
+asls20: SPIN_ON_SPINLOCK ecx,<short asls10>
+endif
+
+if DBG
+cPublicFpo 2,1
+asls99: movzx eax, al
+ push eax ; put old irql where we can find it
+ stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return
+endif
+ fstRET KeAcquireSpinLockRaiseToSynch
+fstENDP KeAcquireSpinLockRaiseToSynch
+
+ PAGE
+ SUBTTL "Release Kernel Spin Lock"
+
+;++
+;
+; VOID
+; KfReleaseSpinLock (
+; IN PKSPIN_LOCK SpinLock,
+; IN KIRQL NewIrql
+; )
+;
+; Routine Description:
+;
+; This function releases a kernel spin lock and lowers to the new irql
+;
+; In a UP hal spinlock serialization is accomplished by raising the
+; IRQL to DISPATCH_LEVEL. The SpinLock is not used; however, for
+; debugging purposes if the UP hal is compiled with the NT_UP flag
+; not set (ie, MP) we use the SpinLock.
+;
+; Arguments:
+;
+; (ecx) = SpinLock Supplies a pointer to an executive spin lock.
+; (dl) = NewIrql New irql value to set
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+align 16
+cPublicFastCall KfReleaseSpinLock ,2
+cPublicFpo 0,0
+ifndef NT_UP
+ RELEASE_SPINLOCK ecx ; release it
+endif
+ xor ecx, ecx
+if DBG
+ cmp dl, PCR[PcIrql]
+ ja short rsl99
+endif
+ pushfd
+ cli
+ mov PCR[PcIrql], dl ; store old irql
+ mov cl, dl ; (ecx) = 32bit extended OldIrql
+ mov edx, PCR[PcIRR]
+ and edx, FindHigherIrqlMask[ecx*4] ; (edx) is the bitmask of
+ ; pending interrupts we need to
+ jne short rsl20 ; dispatch now.
+
+ popfd
+ fstRet KfReleaseSpinLock ; all done
+
+if DBG
+rsl99: stdCall _KeBugCheck, <IRQL_NOT_LESS_OR_EQUAL> ; never return
+endif
+
+cPublicFpo 0,1
+rsl20: bsr ecx, edx ; (ecx) = Pending irq level
+ cmp ecx, DISPATCH_LEVEL
+ jle short rsl40
+
+ mov eax, PCR[PcIDR] ; Clear all the interrupt
+ SET_8259_MASK ; masks
+rsl40:
+ mov edx, 1
+ shl edx, cl
+ xor PCR[PcIRR], edx ; clear bit in IRR
+ call SWInterruptHandlerTable[ecx*4] ; Dispatch the pending int.
+ popfd
+
+cPublicFpo 0, 0
+ fstRet KfReleaseSpinLock ; all done
+
+fstENDP KfReleaseSpinLock
+
+;++
+;
+; VOID
+; FASTCALL
+; ExAcquireFastMutex (
+; IN PFAST_MUTEX FastMutex
+; )
+;
+; Routine description:
+;
+; This function acquire ownership of the FastMutex
+;
+; Arguments:
+;
+; (ecx) = FastMutex - Supplies a pointer to the fast mutex
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+cPublicFastCall ExAcquireFastMutex,1
+cPublicFpo 0,0
+ mov al, PCR[PcIrql] ; (cl) = OldIrql
+if DBG
+ cmp al, APC_LEVEL ; Is OldIrql > NewIrql?
+ ja short afm99 ; Yes, bugcheck
+
+ mov edx, PCR[PcPrcb]
+ mov edx, [edx].PbCurrentThread ; (edx) = Current Thread
+ cmp [ecx].FmOwner, edx ; Already owned by this thread?
+ je short afm98 ; Yes, error
+endif
+
+ mov byte ptr PCR[PcIrql], APC_LEVEL ; Set NewIrql
+ LOCK_DEC dword ptr [ecx].FmCount ; Get count
+ jz short afm_ret ; The owner? Yes, Done
+
+ inc dword ptr [ecx].FmContention
+
+cPublicFpo 0,2
+ push eax ; save OldIrql
+ push ecx ; Save FAST_MUTEX
+ add ecx, FmEvent ; Wait on Event
+
+ stdCall _KeWaitForSingleObject,<ecx,WrExecutive,0,0,0>
+
+ pop ecx ; (ecx) = FAST_MUTEX
+ pop eax ; (al) = OldIrql
+
+cPublicFpo 1,0
+afm_ret:
+
+if DBG
+ cli
+ mov edx, PCR[PcPrcb]
+ mov edx, [edx].PbCurrentThread ; (edx) = Current Thread
+ sti
+ mov [ecx].FmOwner, edx ; Save in Fast Mutex
+endif
+ mov byte ptr [ecx].FmOldIrql, al
+ fstRet ExAcquireFastMutex
+
+if DBG
+afm98: stdCall _KeBugCheck, <eax> ; never return
+afm99: stdCall _KeBugCheck, <IRQL_NOT_LESS_OR_EQUAL> ; never return
+ fstRet ExAcquireFastMutex
+endif
+
+fstENDP ExAcquireFastMutex
+
+
+;++
+;
+; VOID
+; FASTCALL
+; ExReleaseFastMutex (
+; IN PFAST_MUTEX FastMutex
+; )
+;
+; Routine description:
+;
+; This function releases ownership of the FastMutex
+;
+; Arguments:
+;
+; (ecx) = FastMutex - Supplies a pointer to the fast mutex
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+cPublicFastCall ExReleaseFastMutex,1
+cPublicFpo 0,0
+ xor eax, eax
+if DBG
+ cli
+ mov edx, PCR[PcPrcb]
+ mov edx, [edx].PbCurrentThread ; (edx) = CurrentThread
+ sti
+ cmp [ecx].FmOwner, edx ; Owner == CurrentThread?
+ jne short rfm_threaderror ; No, bugcheck
+endif
+ or byte ptr [ecx].FmOwner, 1 ; not the owner anymore
+
+ mov al, byte ptr [ecx].FmOldIrql ; (eax) = OldIrql
+ LOCK_ADD dword ptr [ecx].FmCount, 1 ; Remove our count
+ js short rfm05 ; if < 0, set event
+ jnz short rfm10 ; if != 0, don't set event
+
+rfm05:
+cPublicFpo 0,2
+ push eax ; Save OldIrql
+ add ecx, FmEvent
+ stdCall _KeSetEventBoostPriority, <ecx, 0>
+ pop eax
+
+cPublicFpo 0,0
+rfm10:
+ cli
+ mov PCR[PcIrql], eax
+ mov edx, PCR[PcIRR]
+ and edx, FindHigherIrqlMask[eax*4] ; (edx) is the bitmask of
+ ; pending interrupts we need to
+ jne short rfm20 ; dispatch now.
+
+ sti
+ fstRet ExReleaseFastMutex ; all done
+if DBG
+rfm_threaderror:
+ stdCall _KeBugCheck, <eax>
+endif
+
+rfm20: bsr ecx, edx ; (ecx) = Pending irq level
+ cmp ecx, DISPATCH_LEVEL
+ jle short rfm40
+
+ mov eax, PCR[PcIDR] ; Clear all the interrupt
+ SET_8259_MASK ; masks
+rfm40:
+ mov edx, 1
+ shl edx, cl
+ xor PCR[PcIRR], edx ; clear bit in IRR
+ call SWInterruptHandlerTable[ecx*4] ; Dispatch the pending int.
+ sti
+ fstRet ExReleaseFastMutex ; all done
+fstENDP ExReleaseFastMutex
+
+;++
+;
+; BOOLEAN
+; FASTCALL
+; ExTryToAcquireFastMutex (
+; IN PFAST_MUTEX FastMutex
+; )
+;
+; Routine description:
+;
+; This function acquire ownership of the FastMutex
+;
+; Arguments:
+;
+; (ecx) = FastMutex - Supplies a pointer to the fast mutex
+;
+; Return Value:
+;
+; Returns TRUE if the FAST_MUTEX was acquired; otherwise false
+;
+;--
+
+cPublicFastCall ExTryToAcquireFastMutex,1
+cPublicFpo 0,0
+ mov al, PCR[PcIrql] ; (al) = OldIrql
+
+if DBG
+ cmp al, APC_LEVEL ; Is OldIrql > NewIrql?
+ ja short tam99 ; Yes, bugcheck
+endif
+
+;
+; Try to acquire - but needs to support 386s.
+; *** Warning: This code is NOT MP safe ***
+; But, we know that this hal really only runs on UP machines
+;
+ cli
+ cmp dword ptr [ecx].FmCount, 1 ; Busy?
+ jne short tam20 ; Yes, abort
+
+ mov dword ptr [ecx].FmCount, 0 ; acquire count
+
+if DBG
+ mov edx, PCR[PcPrcb]
+ mov edx, [edx].PbCurrentThread ; (edx) = Current Thread
+ mov [ecx].FmOwner, edx ; Save in Fast Mutex
+endif
+ mov PCR[PcIrql], APC_LEVEL
+ sti
+ mov byte ptr [ecx].FmOldIrql, al
+ mov eax, 1 ; return TRUE
+ fstRet ExTryToAcquireFastMutex
+
+tam20: sti
+ xor eax, eax ; return FALSE
+ fstRet ExTryToAcquireFastMutex ; all done
+
+if DBG
+tam99: stdCall _KeBugCheck, <IRQL_NOT_LESS_OR_EQUAL> ; never return
+ xor eax, eax ; return FALSE
+ fstRet ExTryToAcquireFastMutex
+endif
+
+fstENDP ExTryToAcquireFastMutex
+
+_TEXT$01 ends
+
+ end
diff --git a/private/ntos/nthals/halx86/i386/ixmca.c b/private/ntos/nthals/halx86/i386/ixmca.c
new file mode 100644
index 000000000..eea051e49
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixmca.c
@@ -0,0 +1,868 @@
+/*++
+
+Module Name:
+
+ ixmca.c
+
+Abstract:
+
+ HAL component of the Machine Check Architecture.
+ All exported MCA functionality is present in this file.
+
+Author:
+
+ Srikanth Kambhatla (Intel)
+
+Revision History:
+
+ Anil Aggarwal (Intel)
+ Changes incorporated as per design review with Microsoft
+
+--*/
+
+#include <bugcodes.h>
+#include <halp.h>
+
+//
+// Structure to keep track of MCA features available on installed hardware
+//
+
+typedef struct _MCA_INFO {
+ FAST_MUTEX Mutex;
+ UCHAR NumBanks; // Number of Banks present
+ ULONGLONG Bank0Config; // Bank0 configuration setup by BIOS.
+ // This will be used as mask when
+ // setting up bank 0
+ MCA_DRIVER_INFO DriverInfo; // Info about registered driver
+ KDPC Dpc; // DPC object for MCA
+
+} MCA_INFO, *PMCA_INFO;
+
+
+//
+// Default MCA Bank configuration
+//
+#define MCA_DEFAULT_BANK_CONF 0xFFFFFFFFFFFFFFFF
+
+//
+// MCA architecture related defines
+//
+
+#define MCA_NUM_REGS 4
+#define MCA_CNT_MASK 0xFF
+#define MCG_CTL_PRESENT 0x100
+
+#define MCE_VALID 0x01
+
+//
+// MSR register addresses for MCA
+//
+
+#define MCG_CAP 0x179
+#define MCG_STATUS 0x17a
+#define MCG_CTL 0x17b
+#define MC0_CTL 0x400
+#define MC0_STATUS 0x401
+#define MC0_ADDR 0x402
+#define MC0_MISC 0x403
+
+#define PENTIUM_MC_ADDR 0x0
+#define PENTIUM_MC_TYPE 0x1
+
+//
+// Writing all 1's to MCG_CTL register enables logging.
+//
+#define MCA_MCGCTL_ENABLE_LOGGING 0xffffffff
+
+//
+// Bit interpretation of MCG_STATUS register
+//
+#define MCG_MC_INPROGRESS 0x4
+#define MCG_EIP_VALID 0x2
+#define MCG_RESTART_EIP_VALID 0x1
+
+//
+// For the function that reads the error reporting bank log, the type of error we
+// are interested in
+//
+#define MCA_GET_ANY_ERROR 0x1
+#define MCA_GET_NONRESTARTABLE_ERROR 0x2
+
+
+//
+// Global Varibles
+//
+
+MCA_INFO HalpMcaInfo;
+extern KAFFINITY HalpActiveProcessors;
+extern UCHAR HalpClockMcaQueueDpc;
+
+extern UCHAR MsgMCEPending[];
+extern WCHAR rgzSessionManager[];
+extern WCHAR rgzEnableMCE[];
+extern WCHAR rgzEnableMCA[];
+
+
+//
+// External prototypes
+//
+
+VOID
+HalpMcaCurrentProcessorSetTSS (
+ VOID
+ );
+
+VOID
+HalpSetCr4MCEBit (
+ VOID
+ );
+
+//
+// Internal prototypes
+//
+
+VOID
+HalpMcaInit (
+ VOID
+ );
+
+NTSTATUS
+HalpMcaReadProcessorException (
+ OUT PMCA_EXCEPTION Exception,
+ IN BOOLEAN NonRestartableOnly
+ );
+
+VOID
+HalpMcaCurrentProcessorSetConfig (
+ VOID
+ );
+
+VOID
+HalpMcaQueueDpc(
+ VOID
+ );
+
+VOID
+HalpMcaGetConfiguration (
+ OUT PULONG MCEEnabled,
+ OUT PULONG MCAEnabled
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT, HalpMcaInit)
+#pragma alloc_text(INIT, HalpMcaCurrentProcessorSetConfig)
+#pragma alloc_text(INIT, HalpMcaGetConfiguration)
+#pragma alloc_text(PAGE, HalpGetMcaLog)
+#pragma alloc_text(PAGE, HalpMcaRegisterDriver)
+#endif
+
+
+//
+// All the initialization code for MCA goes here
+//
+
+VOID
+HalpMcaInit (
+ VOID
+ )
+
+/*++
+ Routine Description:
+ This routine is called to do all the initialization work
+
+ Arguments:
+ None
+
+ Return Value:
+ STATUS_SUCCESS if successful
+ error status otherwise
+--*/
+
+{
+ ULONGLONG MsrCapability;
+ KIRQL OldIrql;
+ PKTHREAD Thread;
+ KAFFINITY ActiveProcessors, CurrentAffinity;
+ ULONGLONG MsrMceType;
+ ULONG MCEEnabled;
+ ULONG MCAEnabled;
+
+ if ( (!(HalpFeatureBits & HAL_MCE_PRESENT)) &&
+ (!(HalpFeatureBits & HAL_MCA_PRESENT)) ) {
+
+ return; // nothing to do
+ }
+
+ HalpMcaGetConfiguration(&MCEEnabled, &MCAEnabled);
+
+ if ( (HalpFeatureBits & HAL_MCE_PRESENT) &&
+ (!(HalpFeatureBits & HAL_MCA_PRESENT)) ) {
+
+ if (MCEEnabled == FALSE) {
+
+ // User has not enabled MCE capability.
+ HalpFeatureBits &= ~(HAL_MCE_PRESENT | HAL_MCA_PRESENT);
+
+ return;
+ }
+
+#if DBG
+ DbgPrint("MCE feature is enabled via registry\n");
+#endif // DBG
+
+ MsrMceType = RDMSR(PENTIUM_MC_TYPE);
+
+ if (((PLARGE_INTEGER)(&MsrMceType))->LowPart & MCE_VALID) {
+
+ //
+ // On an AST PREMMIA MX machine we seem to have a Machine Check Pending
+ // always.
+ //
+
+ HalDisplayString(MsgMCEPending);
+
+ HalpFeatureBits &= ~(HAL_MCE_PRESENT | HAL_MCA_PRESENT);
+
+ return;
+ }
+ }
+
+ //
+ // If MCA is available, find out the number of banks available and
+ // also get the platform specific bank 0 configuration
+ //
+
+ if ( HalpFeatureBits & HAL_MCA_PRESENT ) {
+
+ if (MCAEnabled == FALSE) {
+
+ /* User has disabled MCA capability. */
+#if DBG
+ DbgPrint("MCA feature is disabled via registry\n");
+#endif // DBG
+
+ HalpFeatureBits &= ~(HAL_MCE_PRESENT | HAL_MCA_PRESENT);
+ return;
+ }
+
+ MsrCapability = RDMSR(MCG_CAP);
+ HalpMcaInfo.NumBanks = (UCHAR)(MsrCapability & MCA_CNT_MASK);
+
+ //
+ // Find out the Bank 0 configuration setup by BIOS. This will be used
+ // as a mask when writing to Bank 0
+ //
+
+ HalpMcaInfo.Bank0Config = RDMSR(MC0_CTL);
+ }
+
+ if ( (HalpFeatureBits & HAL_MCA_PRESENT) ||
+ (HalpFeatureBits & HAL_MCE_PRESENT) ) {
+
+ ASSERT(HalpFeatureBits & HAL_MCE_PRESENT);
+
+ //
+ // This lock synchronises access to the log area when we call the
+ // logger on multiple processors.
+ //
+
+ ExInitializeFastMutex (&HalpMcaInfo.Mutex);
+
+ //
+ // Initialize on each processor
+ //
+
+ Thread = KeGetCurrentThread ();
+ ActiveProcessors = HalpActiveProcessors;
+ for (CurrentAffinity = 1; ActiveProcessors; CurrentAffinity <<= 1) {
+
+ if (ActiveProcessors & CurrentAffinity) {
+ ActiveProcessors &= ~CurrentAffinity;
+ KeSetAffinityThread (Thread, CurrentAffinity);
+
+ //
+ // Initialize MCA support on this processor
+ //
+
+ OldIrql = KfRaiseIrql(HIGH_LEVEL);
+
+ HalpMcaCurrentProcessorSetTSS();
+ HalpMcaCurrentProcessorSetConfig();
+
+ KfLowerIrql(OldIrql);
+ }
+ }
+
+ //
+ // Restore threads affinity
+ //
+
+ KeSetAffinityThread (Thread, HalpActiveProcessors);
+ }
+}
+
+
+VOID
+HalpMcaCurrentProcessorSetConfig (
+ VOID
+ )
+/*++
+
+ Routine Description:
+
+ This routine sets/modifies the configuration of the machine check
+ architecture on the current processor. Input is specification of
+ the control register MCi_CTL for each bank of the MCA architecture.
+ which controls the generation of machine check exceptions for errors
+ logged to that bank.
+
+ If MCA is not available on this processor, check if MCE is available.
+ If so, enable MCE in CR4
+
+ Arguments:
+
+ Context: Array of values of MCi_CTL for each bank of MCA.
+ If NULL, use MCA_DEFAULT_BANK_CONF values for each bank
+
+ Return Value:
+
+ None
+
+--*/
+{
+ ULONGLONG MciCtl;
+ ULONGLONG McgCap;
+ ULONGLONG McgCtl;
+ ULONG BankNum;
+
+
+ if (HalpFeatureBits & HAL_MCA_PRESENT) {
+ //
+ // MCA is available. Initialize MCG_CTL register if present
+ // Writing all 1's enable MCE or MCA Error Exceptions
+ //
+
+ McgCap = RDMSR(MCG_CAP);
+
+ if (McgCap & MCG_CTL_PRESENT) {
+ McgCtl = MCA_MCGCTL_ENABLE_LOGGING;
+ WRMSR(MCG_CTL, McgCtl);
+ }
+
+ //
+ // Enable all MCA errors
+ //
+ for ( BankNum = 0; BankNum < HalpMcaInfo.NumBanks; BankNum++ ) {
+
+ //
+ // Use MCA_DEFAULT_BANK_CONF for each bank
+ //
+
+ MciCtl = MCA_DEFAULT_BANK_CONF;
+
+ //
+ // If this is bank 0, use HalpMcaInfo.Bank0Config as a mask
+ //
+ if (BankNum == 0) {
+ MciCtl &= HalpMcaInfo.Bank0Config;
+ }
+
+ WRMSR(MC0_CTL + (BankNum * MCA_NUM_REGS), MciCtl);
+
+ //
+ // Clear the MCi_STATUS registers also
+ //
+ WRMSR(MC0_STATUS + (BankNum * MCA_NUM_REGS), 0x0);
+ }
+ }
+
+ //
+ // Enable MCE bit in CR4
+ //
+
+ HalpSetCr4MCEBit();
+}
+
+
+NTSTATUS
+HalpMcaRegisterDriver(
+ IN PMCA_DRIVER_INFO DriverInfo
+ )
+/*++
+ Routine Description:
+ This routine is called by the driver (via HalSetSystemInformation)
+ to register its presence. Only one driver can be registered at a time.
+
+ Arguments:
+ DriverInfo: Contains info about the callback routine and the DeviceObject
+
+ Return Value:
+ Unless a MCA driver is already registered OR one of the two callback
+ routines are NULL, this routine returns Success.
+--*/
+
+{
+ KIRQL OldIrql;
+ PVOID UnlockHandle;
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+
+ Status = STATUS_UNSUCCESSFUL;
+
+ if ((HalpFeatureBits & HAL_MCE_PRESENT) && DriverInfo->DpcCallback) {
+
+ ExAcquireFastMutex (&HalpMcaInfo.Mutex);
+
+ //
+ // Register driver
+ //
+
+ if (!HalpMcaInfo.DriverInfo.DpcCallback) {
+
+ // Initialize the DPC object
+ KeInitializeDpc(
+ &HalpMcaInfo.Dpc,
+ DriverInfo->DpcCallback,
+ DriverInfo->DeviceContext
+ );
+
+ // register driver
+ HalpMcaInfo.DriverInfo.ExceptionCallback = DriverInfo->ExceptionCallback;
+ HalpMcaInfo.DriverInfo.DpcCallback = DriverInfo->DpcCallback;
+ HalpMcaInfo.DriverInfo.DeviceContext = DriverInfo->DeviceContext;
+ Status = STATUS_SUCCESS;
+ }
+
+ ExReleaseFastMutex (&HalpMcaInfo.Mutex);
+ }
+
+ return Status;
+}
+
+
+NTSTATUS
+HalpGetMcaLog (
+ OUT PMCA_EXCEPTION Exception,
+ OUT PULONG ReturnedLength
+ )
+/*++
+ Routine Description:
+ This is the entry point for driver to read the bank logs
+ Called by HaliQuerySystemInformation()
+
+ Arguments:
+ Buffer: into which the error is reported
+ BufferSize: Size of the passed buffer
+ Length: of this buffer
+
+ Return Value:
+ Success or failure
+
+--*/
+{
+ KAFFINITY ActiveProcessors, CurrentAffinity;
+ PKTHREAD Thread;
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ if (! (HalpFeatureBits & HAL_MCA_PRESENT)) {
+ return(STATUS_NO_SUCH_DEVICE);
+ }
+
+
+ Thread = KeGetCurrentThread ();
+ ActiveProcessors = HalpActiveProcessors;
+ Status = STATUS_NOT_FOUND;
+
+ ExAcquireFastMutex (&HalpMcaInfo.Mutex);
+
+ for (CurrentAffinity = 1; ActiveProcessors; CurrentAffinity <<= 1) {
+
+ if (ActiveProcessors & CurrentAffinity) {
+
+ ActiveProcessors &= ~CurrentAffinity;
+ KeSetAffinityThread (Thread, CurrentAffinity);
+
+ //
+ // Check this processor for an exception
+ //
+
+ Status = HalpMcaReadProcessorException (Exception, FALSE);
+
+ //
+ // If found, return current information
+ //
+
+ if (Status != STATUS_NOT_FOUND) {
+ ASSERT (Status != STATUS_SEVERITY_ERROR);
+
+ *ReturnedLength = sizeof(MCA_EXCEPTION);
+ break;
+ }
+ }
+ }
+
+ //
+ // Restore threads affinity, release mutex, and return
+ //
+
+ KeSetAffinityThread (Thread, HalpActiveProcessors);
+ ExReleaseFastMutex (&HalpMcaInfo.Mutex);
+ return Status;
+}
+
+
+#if DBG
+//
+// In checked build, we allocate 4K stack for ourselves and hence there is
+// no need to switch to the stack of double fault handler. We can
+// directly bugcheck without switching stack.
+//
+#define HalpMcaSwitchMcaExceptionStackAndBugCheck KeBugCheckEx
+#else
+NTKERNELAPI
+VOID
+HalpMcaSwitchMcaExceptionStackAndBugCheck(
+ IN ULONG BugCheckCode,
+ IN ULONG BugCheckParameter1,
+ IN ULONG BugCheckParameter2,
+ IN ULONG BugCheckParameter3,
+ IN ULONG BugCheckParameter4
+ );
+#endif // DBG
+
+// Set the following to check async capability
+
+BOOLEAN NoMCABugCheck = FALSE;
+
+VOID
+HalpMcaExceptionHandler (
+ VOID
+ )
+
+/*++
+ Routine Description:
+ This is the MCA exception handler.
+
+ Arguments:
+ None
+
+ Return Value:
+ None
+--*/
+
+{
+ NTSTATUS Status;
+ MCA_EXCEPTION BankLog;
+ ULONG p1, p2;
+ ULONGLONG McgStatus, p3;
+
+ BankLog.VersionNumber = 1;
+
+ if (!(HalpFeatureBits & HAL_MCA_PRESENT) ) {
+
+ //
+ // If we have ONLY MCE (and not MCA), read the MC_ADDR and MC_TYPE
+ // MSRs, print the values and bugcheck as the errors are not
+ // restartable.
+ //
+
+ BankLog.ExceptionType = HAL_MCE_RECORD;
+ BankLog.u.Mce.Address = RDMSR(PENTIUM_MC_ADDR);
+ BankLog.u.Mce.Type = RDMSR(PENTIUM_MC_TYPE);
+ Status = STATUS_SEVERITY_ERROR;
+
+ //
+ // Parameters for bugcheck
+ //
+
+ p1 = ((PLARGE_INTEGER)(&BankLog.u.Mce.Type))->LowPart;
+ p2 = 0;
+ p3 = BankLog.u.Mce.Address;
+
+ } else {
+
+ McgStatus = RDMSR(MCG_STATUS);
+ ASSERT( (McgStatus & MCG_MC_INPROGRESS) != 0);
+
+ Status = HalpMcaReadProcessorException (&BankLog, TRUE);
+
+ //
+ // Clear MCIP bit in MCG_STATUS register
+ //
+
+ McgStatus = 0;
+ WRMSR(MCG_STATUS, McgStatus);
+
+ //
+ // Parameters for bugcheck
+ //
+
+ p1 = BankLog.u.Mca.BankNumber;
+ p2 = BankLog.u.Mca.Address.Address;
+ p3 = BankLog.u.Mca.Status.QuadPart;
+ }
+
+ if (Status == STATUS_SEVERITY_ERROR) {
+
+ //
+ // Call the exception callback of the driver so that
+ // the error can be logged to NVRAM
+ //
+
+ if (HalpMcaInfo.DriverInfo.ExceptionCallback) {
+ HalpMcaInfo.DriverInfo.ExceptionCallback (
+ HalpMcaInfo.DriverInfo.DeviceContext,
+ &BankLog
+ );
+ }
+
+ if (!NoMCABugCheck) {
+
+ //
+ // Bugcheck
+ //
+
+ HalpMcaSwitchMcaExceptionStackAndBugCheck(
+ MACHINE_CHECK_EXCEPTION,
+ p1,
+ p2,
+ ((PLARGE_INTEGER)(&p3))->HighPart,
+ ((PLARGE_INTEGER)(&p3))->LowPart
+ );
+
+ // NOT REACHED
+ }
+ }
+
+ //
+ // Must be restartable. Indicate to the timer tick routine that a
+ // DPC needs queued for MCA driver.
+ //
+
+ if (HalpMcaInfo.DriverInfo.DpcCallback) {
+ HalpClockMcaQueueDpc = 1;
+ }
+}
+
+VOID
+HalpMcaQueueDpc(
+ VOID
+ )
+/*++
+ Routine Description: Gets called from the timer tick to check if DPC
+ needs to be queued
+
+--*/
+
+{
+ KeInsertQueueDpc(
+ &HalpMcaInfo.Dpc,
+ NULL,
+ NULL
+ );
+}
+
+
+NTSTATUS
+HalpMcaReadProcessorException (
+ OUT PMCA_EXCEPTION Exception,
+ IN BOOLEAN NonRestartableOnly
+ )
+/*++
+
+ Routine Description:
+
+ This routine logs the errors from the MCA banks on one processor.
+ Necessary checks for the restartability are performed. The routine
+ 1> Checks for restartability, and for each bank identifies valid bank
+ entries and logs error.
+ 2> If the error is not restartable provides additional information about
+ bank and the MCA registers.
+ 3> Resets the Status registers for each bank
+
+ Arguments:
+ LogExcept: Into which we log the error if found
+ NonRestartableOnly: Get any error vs. look for error that is not-restartable
+
+ Return Values:
+ STATUS_SEVERITY_ERROR: Detected non-restartable error.
+ STATUS_SUCCESS: Successfully logged bank values
+ STATUS_NOT_FOUND: No error found on any bank
+
+--*/
+{
+ ULONGLONG McgStatus;
+ UCHAR BankNumber;
+ MCI_STATS istatus;
+ NTSTATUS ReturnStatus;
+ ULONG eflags;
+
+ //
+ // Read the global status register
+ //
+
+ McgStatus = RDMSR(MCG_STATUS);
+
+ //
+ // scan banks on current processor and log contents of first valid bank
+ // reporting error. Once we find a valid error, no need to read remaining
+ // banks. It is the application responsibility to read more errors.
+ //
+
+ ReturnStatus = STATUS_NOT_FOUND;
+
+ for (BankNumber = 0; BankNumber < HalpMcaInfo.NumBanks; BankNumber++) {
+
+ //
+ // Read the Status MSR of individual bank
+ //
+
+ istatus.QuadPart = RDMSR(MC0_STATUS + BankNumber * MCA_NUM_REGS);
+
+
+ if (istatus.MciStats.Valid == 0) {
+ // No error in this bank.
+ continue;
+
+ }
+
+ //
+ // When MCIP bit is set, the execution can be restarted when
+ // (MCi_STATUS.DAM == 0) && (MCG_STATUS.RIPV == 1)
+ //
+
+ if ((McgStatus & MCG_MC_INPROGRESS) &&
+ (!(McgStatus & MCG_RESTART_EIP_VALID) ||
+ istatus.MciStats.Damage)) {
+
+ ReturnStatus = STATUS_SEVERITY_ERROR;
+
+ } else if (NonRestartableOnly == FALSE) {
+
+ ReturnStatus = STATUS_SUCCESS;
+
+ } else {
+
+ // Not the desired type error available here
+ continue;
+ }
+
+ //
+ // Complete exception record
+ //
+
+ Exception->VersionNumber = 1;
+ Exception->ExceptionType = HAL_MCA_RECORD;
+ Exception->TimeStamp.QuadPart = 0;
+ Exception->u.Mca.Address.QuadPart = 0;
+ Exception->u.Mca.Misc = 0;
+ Exception->u.Mca.BankNumber = BankNumber;
+ Exception->u.Mca.Status = istatus;
+
+ Exception->ProcessorNumber = KeGetCurrentProcessorNumber();
+
+ if (KeGetCurrentIrql() != CLOCK2_LEVEL) {
+ KeQuerySystemTime(&Exception->TimeStamp);
+ }
+
+ if (istatus.MciStats.AddressValid) {
+ Exception->u.Mca.Address.QuadPart = RDMSR(MC0_ADDR + BankNumber * MCA_NUM_REGS);
+ }
+
+ if (istatus.MciStats.MiscValid) {
+ Exception->u.Mca.Misc = RDMSR(MC0_MISC + BankNumber * MCA_NUM_REGS);
+ }
+
+ if (ReturnStatus != STATUS_SEVERITY_ERROR) {
+
+ // Clear MCi_STATUS register (not a falal error)
+
+ WRMSR(MC0_STATUS + BankNumber * MCA_NUM_REGS, 0);
+ }
+
+ //
+ // When the Valid bit of status register is cleared, hardware may write
+ // a new buffered error report into the error reporting area. The
+ // serializing instruction is required to permit the update to complete
+ //
+
+ HalpSerialize ();
+
+ //
+ // Found entry, done
+ //
+
+ break;
+ }
+
+ return(ReturnStatus);
+}
+
+VOID
+HalpMcaGetConfiguration (
+ OUT PULONG MCEEnabled,
+ OUT PULONG MCAEnabled
+)
+
+/*++
+
+Routine Description:
+
+ This routine stores the Machine Check configuration information.
+
+Arguments:
+
+ MCEEnabled - Pointer to the MCEEnabled indicator.
+ 0 = False, 1 = True (0 if value not present in Registry).
+
+ MCAEnabled - Pointer to the MCAEnabled indicator.
+ 0 = False, 1 = True (1 if value not present in Registry).
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ RTL_QUERY_REGISTRY_TABLE Parameters[3];
+ ULONG DefaultDataMCE;
+ ULONG DefaultDataMCA;
+
+
+ RtlZeroMemory(Parameters, sizeof(Parameters));
+ DefaultDataMCE = *MCEEnabled = FALSE;
+ DefaultDataMCA = *MCAEnabled = TRUE;
+
+ //
+ // Gather all of the "user specified" information from
+ // the registry.
+ //
+
+ Parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ Parameters[0].Name = rgzEnableMCE;
+ Parameters[0].EntryContext = MCEEnabled;
+ Parameters[0].DefaultType = REG_DWORD;
+ Parameters[0].DefaultData = &DefaultDataMCE;
+ Parameters[0].DefaultLength = sizeof(ULONG);
+
+ Parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ Parameters[1].Name = rgzEnableMCA;
+ Parameters[1].EntryContext = MCAEnabled;
+ Parameters[1].DefaultType = REG_DWORD;
+ Parameters[1].DefaultData = &DefaultDataMCA;
+ Parameters[1].DefaultLength = sizeof(ULONG);
+
+ RtlQueryRegistryValues(
+ RTL_REGISTRY_CONTROL | RTL_REGISTRY_OPTIONAL,
+ rgzSessionManager,
+ Parameters,
+ NULL,
+ NULL
+ );
+}
diff --git a/private/ntos/nthals/halx86/i386/ixmcaa.asm b/private/ntos/nthals/halx86/i386/ixmcaa.asm
new file mode 100644
index 000000000..229621892
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixmcaa.asm
@@ -0,0 +1,420 @@
+;++
+;Module Name
+; imca.asm
+;
+;Abstract:
+; Assembly support needed for Intel MCA
+;
+; Author:
+; Anil Aggarwal (Intel Corp)
+;
+;Revision History:
+;
+;
+;--
+
+.586p
+ .xlist
+include hal386.inc
+include callconv.inc
+include i386\kimacro.inc
+ .list
+
+ EXTRNP _HalpMcaExceptionHandler,0
+ EXTRNP _KeBugCheckEx,5,IMPORT
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; DATA Segment
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+_DATA SEGMENT PARA PUBLIC 'DATA'
+;
+; MCA Exception task stack
+;
+
+MINIMUM_TSS_SIZE EQU TssIoMaps
+
+if DBG
+;
+; If we use DbgPrint, we need a larger stack
+;
+MCA_EXCEPTION_STACK_SIZE EQU 01000H
+else
+MCA_EXCEPTION_STACK_SIZE EQU 0100H
+endif
+
+KGDT_MCA_TSS EQU 0A0H
+
+
+ ;
+ ; TSS for MCA Exception
+ ;
+ align 16
+
+ public _HalpMcaExceptionTSS
+_HalpMcaExceptionTSS label byte
+ db MINIMUM_TSS_SIZE dup(0)
+
+ ;
+ ; Stack for MCA exception task
+ ;
+
+ public _HalpMcaExceptionStack
+ db MCA_EXCEPTION_STACK_SIZE dup ("*")
+_HalpMcaExceptionStack label byte
+
+_DATA ends
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; TEXT Segment
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+_TEXT SEGMENT PARA PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ .586p
+
+;++
+;ULONGLONG
+;FASTCALL
+;RDMSR(
+; IN ULONG MsrAddress
+; )
+; Routine Description:
+; This function reads an MSR
+;
+; Arguments:
+; Msr: The address of MSR to be read
+;
+; Return Value:
+; Returns the low 32 bit of MSR in eax and high 32 bits of MSR in edx
+;
+;--
+cPublicFastCall RDMSR,1
+
+ rdmsr
+ fstRET RDMSR
+
+fstENDP RDMSR
+
+;++
+;
+;VOID
+;WRMSR(
+; IN ULONG MsrAddress,
+; IN ULONGLONG MsrValue
+; )
+; Routine Description:
+; This function writes an MSR
+;
+; Arguments:
+; Msr: The address of MSR to be written
+; Data: The value to be written to the MSR register
+;
+; Return Value:
+; None
+;
+;--
+
+cPublicProc _WRMSR,3
+
+ mov ecx, [esp + 4] ; MsrAddress
+ mov eax, [esp + 8] ; Low 32 bits of MsrValue
+ mov edx, [esp + 12] ; High 32 bits of MsrValue
+
+ wrmsr
+ stdRET _WRMSR
+
+stdENDP _WRMSR
+
+;++
+;
+;VOID
+;HalpSerialize(
+; VOID
+; )
+;
+; Routine Description:
+; This function implements the fence operation for out-of-order execution
+;
+; Arguments:
+; None
+;
+; Return Value:
+; None
+;
+;--
+
+cPublicProc _HalpSerialize,0
+
+ push ebx
+ xor eax, eax
+ cpuid
+ pop ebx
+
+ stdRET _HalpSerialize
+
+stdENDP _HalpSerialize
+
+
+;++
+;
+; Routine Description:
+;
+; Machine Check exception handler
+;
+;
+; Arguments:
+;
+; Return value:
+;
+; If the error is non-restartable, we will bugcheck.
+; Otherwise, we just return
+;
+;--
+ ASSUME DS:NOTHING, SS:NOTHING, ES:NOTHING
+align dword
+ public _HalpMcaExceptionHandlerWrapper
+_HalpMcaExceptionHandlerWrapper proc
+.FPO (0, 0, 0, 0, 0, 2)
+
+ cli
+
+ ;
+ ; Update the TSS pointer in the PCR to point to the MCA TSS
+ ; (which is what we're running on, or else we wouldn't be here)
+ ;
+
+ push dword ptr PCR[PcTss]
+ mov eax, PCR[PcGdt]
+ mov ch, [eax+KGDT_MCA_TSS+KgdtBaseHi]
+ mov cl, [eax+KGDT_MCA_TSS+KgdtBaseMid]
+ shl ecx, 16
+ mov cx, [eax+KGDT_MCA_TSS+KgdtBaseLow]
+ mov PCR[PcTss], ecx
+
+ ;
+ ; Clear the busy bit in the TSS selector
+ ;
+ mov ecx, PCR[PcGdt]
+ lea eax, [ecx] + KGDT_MCA_TSS
+ mov byte ptr [eax+5], 089h ; 32bit, dpl=0, present, TSS32, not busy
+
+ ;
+ ; Clear Nested Task bit in EFLAGS
+ ;
+ pushfd
+ and [esp], not 04000h
+ popfd
+
+ ;
+ ; Check if there is a bugcheck-able error. If need to bugcheck, the
+ ; caller does it.
+ ;
+ stdCall _HalpMcaExceptionHandler
+
+ ;
+ ; We're back which means that the error was restartable.
+ ;
+
+ pop dword ptr PCR[PcTss] ; restore PcTss
+
+ mov ecx, PCR[PcGdt]
+ lea eax, [ecx] + KGDT_TSS
+ mov byte ptr [eax+5], 08bh ; 32bit, dpl=0, present, TSS32, *busy*
+
+ pushfd ; Set Nested Task bit in EFLAGS
+ or [esp], 04000h ; so iretd will do a tast switch
+ popfd
+
+ iretd ; Return from MCA Exception handler
+ jmp short _HalpMcaExceptionHandlerWrapper
+ ; For next Machine check exception
+
+_HalpMcaExceptionHandlerWrapper endp
+
+;++
+;
+; Routine Description:
+;
+; MCA exception is run off a small stack pointed to by MCA TSS. When
+; the error is non-restartable, this routine is called to switch to a larger
+; stack which is the overlay of ZW thunks (as is done for double fault stack)
+;
+; Arguments:
+;
+; The arguments to KeMachineCheck are passed to this function
+;
+; Return value:
+;
+; Never returns. End up doing the bugcheck.
+;
+;--
+
+cPublicProc _HalpMcaSwitchMcaExceptionStackAndBugCheck,5
+
+ ; Get Task gate descriptor for double fault handler
+ mov ecx, PCR[PcIdt] ; Get IDT address
+ lea eax, [ecx] + 040h ; DF Exception is 8
+
+ ; Get to TSS Descriptor of double fault handler TSS
+ xor ecx, ecx
+ mov cx, word ptr [eax+2]
+ add ecx, PCR[PcGdt]
+
+ ; Get the address of TSS from this TSS Descriptor
+ mov ah, [ecx+KgdtBaseHi]
+ mov al, [ecx+KgdtBaseMid]
+ shl eax, 16
+ mov ax, [ecx+KgdtBaseLow]
+
+ ; Get ESP from DF TSS
+ mov ecx, [eax+038h]
+
+ ; Save the passed arguments before we switch the stacks
+ mov eax, [esp+4]
+ mov ebx, [esp+8]
+ mov edx, [esp+12]
+ mov esi, [esp+16]
+ mov edi, [esp+20]
+
+ ; Use the ZW thunk area for the stack to operate on for crash
+ mov esp, ecx
+
+ stdCall _KeBugCheckEx, <eax, ebx, edx, esi, edi>
+
+ stdRET _HalpMcaSwitchMcaExceptionStackAndBugCheck
+
+stdENDP _HalpMcaSwitchMcaExceptionStackAndBugCheck
+
+_TEXT ends
+
+INIT SEGMENT DWORD PUBLIC 'CODE'
+
+;++
+;VOID
+;HalpMcaCurrentProcessorSetTSS(
+; VOID
+; )
+; Routine Description:
+; This function sets up the TSS for MCA exception 18
+;
+; Arguments:
+; Context: We don't care about this but is there since HalpGenericCall
+; needs one
+;
+; Return Value:
+; None
+;
+;--
+
+cPublicProc _HalpMcaCurrentProcessorSetTSS,0
+
+ ;
+ ; Edit IDT Entry for MCA Exception (18) to contain a task gate
+ ;
+ mov ecx, PCR[PcIdt] ; Get IDT address
+ lea eax, [ecx] + 090h ; MCA Exception is 18
+ mov byte ptr [eax + 5], 085h ; P=1,DPL=0,Type=5
+ mov word ptr [eax + 2], KGDT_MCA_TSS ; TSS Segment Selector
+
+ mov edx, offset FLAT:_HalpMcaExceptionTSS ; the address of TSS in edx
+
+ ;
+ ; Set various fields in TSS
+ ;
+ mov eax, cr3
+ mov [edx + TssCR3], eax
+
+ mov eax, offset FLAT:_HalpMcaExceptionStack; address of MCA Exception stack
+ mov dword ptr [edx+038h], eax ; Set ESP
+ mov dword ptr [edx+TssEsp0], eax ; Set ESP0
+
+ mov dword ptr [edx+020h], offset FLAT:_HalpMcaExceptionHandlerWrapper ; set EIP
+ mov dword ptr [edx+024h], 0 ; set EFLAGS
+ mov word ptr [edx+04ch],KGDT_R0_CODE ; set value for CS
+ mov word ptr [edx+058h],KGDT_R0_PCR ; set value for FS
+ mov [edx+050h], ss
+ mov word ptr [edx+048h],KGDT_R3_DATA OR RPL_MASK ; Es
+ mov word ptr [edx+054h],KGDT_R3_DATA OR RPL_MASK ; Ds
+
+ ;
+ ; Part that gets done in KiInitialiazeTSS()
+ ;
+ mov word ptr [edx + 08], KGDT_R0_DATA ; Set SS0
+ mov word ptr [edx + 060h],0 ; Set LDT
+ mov word ptr [edx + 064h],0 ; Set T bit
+ mov word ptr [edx + 066h],020adh ; I/O Map base address = sizeof(KTSS)+1
+
+ ;
+ ; Edit GDT entry for KGDT_MCA_TSS to create a valid TSS Descriptor
+ ;
+ mov ecx, PCR[PcGdt] ; Get GDT address
+ lea eax, [ecx] + KGDT_MCA_TSS ; offset of MCA TSS in GDT
+ mov ecx, eax
+
+ ;
+ ; Set Type field of TSS Descriptor
+ ;
+ mov byte ptr [ecx + 5], 089H ; P=1, DPL=0, Type = 9
+
+ ;
+ ; Set Base Address field of TSS Descriptor
+ ;
+ mov eax, edx ; TSS address in eax
+ mov [ecx + KgdtBaseLow], ax
+ shr eax, 16
+ mov [ecx + KgdtBaseHi],ah
+ mov [ecx + KgdtBaseMid],al
+
+ ;
+ ; Set Segment limit for TSS Descriptor
+ ;
+ mov eax, MINIMUM_TSS_SIZE
+ mov [ecx + KgdtLimitLow],ax
+
+ stdRET _HalpMcaCurrentProcessorSetTSS
+
+stdENDP _HalpMcaCurrentProcessorSetTSS
+
+
+;++
+;
+;VOID
+;HalpSetCr4MCEBit(
+; VOID
+; )
+;
+; Routine Description:
+; This function sets the CR4.MCE bit
+;
+; Arguments:
+; None
+;
+; Return Value:
+; None
+;
+;--
+
+cPublicProc _HalpSetCr4MCEBit,0
+
+ mov eax, cr4
+ or eax, CR4_MCE
+ mov cr4, eax
+ stdRET _HalpSetCr4MCEBit
+
+stdENDP _HalpSetCr4MCEBit
+
+
+INIT ends
+
+ end
+
diff --git a/private/ntos/nthals/halx86/i386/ixnmi.c b/private/ntos/nthals/halx86/i386/ixnmi.c
new file mode 100644
index 000000000..e00035bd8
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixnmi.c
@@ -0,0 +1,137 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ixnmi.c
+
+Abstract:
+
+ Provides standard x86 NMI handler
+
+Author:
+
+ kenr
+
+Revision History:
+
+--*/
+#include "halp.h"
+#include "bugcodes.h"
+
+#define SYSTEM_CONTROL_PORT_A 0x92
+#define SYSTEM_CONTROL_PORT_B 0x61
+#define EISA_EXTENDED_NMI_STATUS 0x461
+
+UCHAR EisaNMIMsg[] = MSG_NMI_EISA_IOCHKERR;
+
+
+VOID
+HalHandleNMI(
+ IN OUT PVOID NmiInfo
+ )
+/*++
+
+Routine Description:
+
+ Called DURING an NMI. The system will BugCheck when an NMI occurs.
+ This function can return the proper bugcheck code, bugcheck itself,
+ or return success which will cause the system to iret from the nmi.
+
+ This function is called during an NMI - no system services are available.
+ In addition, you don't want to touch any spinlock which is normally
+ used since we may have been interrupted while owning it, etc, etc...
+
+Warnings:
+
+ Do NOT:
+ Make any system calls
+ Attempt to acquire any spinlock used by any code outside the NMI handler
+ Change the interrupt state. Do not execute any IRET inside this code
+
+ Passing data to non-NMI code must be done using manual interlocked
+ functions. (xchg instructions).
+
+Arguments:
+
+ NmiInfo - Pointer to NMI information structure (TBD)
+ - NULL means no NMI information structure was passed
+
+Return Value:
+
+ BugCheck code
+
+--*/
+{
+ UCHAR StatusByte;
+ UCHAR EisaPort;
+ UCHAR c;
+ ULONG port, i;
+
+ HalDisplayString (MSG_HARDWARE_ERROR1);
+ HalDisplayString (MSG_HARDWARE_ERROR2);
+
+ StatusByte = READ_PORT_UCHAR((PUCHAR) SYSTEM_CONTROL_PORT_B);
+
+ if (StatusByte & 0x80) {
+ HalDisplayString (MSG_NMI_PARITY);
+ }
+
+ if (StatusByte & 0x40) {
+ HalDisplayString (MSG_NMI_CHANNEL_CHECK);
+ }
+
+ if (HalpBusType == MACHINE_TYPE_EISA) {
+ //
+ // This is an Eisa machine, check for extnded nmi information...
+ //
+
+ StatusByte = READ_PORT_UCHAR((PUCHAR) EISA_EXTENDED_NMI_STATUS);
+
+ if (StatusByte & 0x80) {
+ HalDisplayString (MSG_NMI_FAIL_SAFE);
+ }
+
+ if (StatusByte & 0x40) {
+ HalDisplayString (MSG_NMI_BUS_TIMEOUT);
+ }
+
+ if (StatusByte & 0x20) {
+ HalDisplayString (MSG_NMI_SOFTWARE_NMI);
+ }
+
+ //
+ // Look for any Eisa expansion board. See if it asserted NMI.
+ //
+
+ for (EisaPort = 1; EisaPort <= 0xf; EisaPort++) {
+ port = (EisaPort << 12) + 0xC80;
+ WRITE_PORT_UCHAR ((PUCHAR) port, 0xff);
+ StatusByte = READ_PORT_UCHAR ((PUCHAR) port);
+
+ if ((StatusByte & 0x80) == 0) {
+ //
+ // Found valid Eisa board, Check to see if it's
+ // if IOCHKERR is asserted.
+ //
+
+ StatusByte = READ_PORT_UCHAR ((PUCHAR) port+4);
+ if (StatusByte & 0x2 && StatusByte != 0xff) {
+ c = (EisaPort > 9 ? 'A'-10 : '0') + EisaPort;
+ for (i=0; EisaNMIMsg[i]; i++) {
+ if (EisaNMIMsg[i] == '%') {
+ EisaNMIMsg[i] = c;
+ HalDisplayString (EisaNMIMsg);
+ EisaNMIMsg[i] = '%';
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ HalDisplayString (MSG_HALT);
+ KeEnterKernelDebugger();
+}
diff --git a/private/ntos/nthals/halx86/i386/ixpcibrd.c b/private/ntos/nthals/halx86/i386/ixpcibrd.c
new file mode 100644
index 000000000..c8b87d31e
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixpcibrd.c
@@ -0,0 +1,1029 @@
+/*++
+
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ ixpcibrd.c
+
+Abstract:
+
+ Get PCI-PCI bridge information
+
+Author:
+
+ Ken Reneris (kenr) 14-June-1994
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "pci.h"
+#include "pcip.h"
+#include "stdio.h"
+
+// debugging only...
+// #define INIT_PCI_BRIDGE 1
+
+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
+//
+
+
+#ifdef INIT_PCI_BRIDGE
+VOID
+HalpGetPciBridgeNeeds (
+ IN ULONG HwType,
+ IN PUCHAR MaxPciBus,
+ IN PCONFIGBRIDGE Current
+ );
+#endif
+
+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)
+
+#ifdef INIT_PCI_BRIDGE
+#pragma alloc_text(PAGE,HalpGetBridgedPCIInterrupt)
+//#pragma alloc_text(PAGE,HalpGetBridgedPCIIrqTable)
+#pragma alloc_text(INIT,HalpGetPciBridgeNeeds)
+#endif
+#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");
+ // skip it...
+ continue;
+ }
+
+ if ((ULONG) CB.PciData->u.type1.SecondaryBus <= CB.BusHandler->BusNumber) {
+
+ // secondary bus number doesn't make any sense. HP Omnibook may
+ // not fill this field in on a virtually disabled pci-pci bridge
+
+ FoundDisabledBridge = TRUE;
+ continue;
+ }
+
+ //
+ // Found a PCI-PCI bridge. Determine it's parent child
+ // releationships
+ //
+
+ 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 releationships 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 limitied to
+ // 256bytes on every 1K aligned boundry 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 + 255;
+ i += 1024;
+
+ // add remaining ranges
+ while (i < j) {
+ HalpAddRange (
+ &ChildBus->BusAddresses->IO,
+ 1, // address space
+ 0, // system base
+ i, // bus address
+ i + 255 // 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+1;
+ return TRUE;
+ }
+
+ if (!FoundDisabledBridge) {
+ return FALSE;
+ }
+
+ DBGMSG ("HAL GetPciData: found disabled pci bridge\n");
+
+#ifdef INIT_PCI_BRIDGE
+ //
+ // We've calculated all the parent's buses known bases & limits.
+ // While doing this a pci-pci bus was found that the bios didn't
+ // configure. This is not expected, and we'll make some guesses
+ // at a configuration here and enable it.
+ //
+ // (this code is primarily for testing the above code since
+ // currently no system bioses actually configure the child buses)
+ //
+
+ 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;
+
+ HalpReadPCIConfig (
+ CB.BusHandler,
+ CB.SlotNumber,
+ CB.PciData,
+ 0,
+ PCI_COMMON_HDR_LENGTH
+ );
+
+ if (CB.PciData->VendorID == PCI_INVALID_VENDORID) {
+ break;
+ }
+
+ if (!IsPciBridge (CB.PciData)) {
+ // not a PCI-PCI bridge
+ continue;
+ }
+
+ if ((CB.PciData->Command & PCI_ENABLE_BUS_MASTER)) {
+ // this PCI bridge is enabled
+ continue;
+ }
+
+ //
+ // We have a disabled bus - assign it a number, then
+ // determine all the requirements of all devices
+ // on the other side of this bridge
+ //
+
+ CB.BusNo = BusNo;
+ HalpGetPciBridgeNeeds (HwType, MaxPciBus, &CB);
+ }
+ }
+ }
+ // preform Rescan
+ return TRUE;
+
+#else
+
+ return FALSE;
+
+#endif
+
+}
+
+VOID
+HalpFixupPciSupportedRanges (
+ IN ULONG MaxBuses
+ )
+/*++
+
+Routine Description:
+
+ PCI-PCI bridged buses only see addresses which their parent
+ bueses support. 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 regiter.
+ 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 contimplate 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 reseved 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);
+}
+
+
+
+#ifdef INIT_PCI_BRIDGE
+
+VOID
+HalpGetPciBridgeNeeds (
+ IN ULONG HwType,
+ IN PUCHAR MaxPciBus,
+ IN PCONFIGBRIDGE Current
+ )
+{
+ ACCESS_MASK DesiredAccess;
+ UNICODE_STRING unicodeString;
+ PUCHAR buffer;
+ HANDLE handle;
+ OBJECT_ATTRIBUTES objectAttributes;
+ PCM_FULL_RESOURCE_DESCRIPTOR Descriptor;
+ PCONFIGURATION_COMPONENT Component;
+ CONFIGBRIDGE CB;
+ ULONG mnum, d, f, i;
+ NTSTATUS status;
+
+ buffer = ExAllocatePool (PagedPool, 1024);
+
+ // init
+ CB.PciData = (PPCI_COMMON_CONFIG) CB.Buffer;
+ CB.SlotNumber.u.bits.Reserved = 0;
+ Current->IO = Current->Memory = Current->PFMemory = 0;
+
+ //
+ // Assign this bridge an ID, and turn on configuration space
+ //
+
+ Current->PciData->u.type1.PrimaryBus = (UCHAR) Current->BusNo;
+ Current->PciData->u.type1.SecondaryBus = (UCHAR) *MaxPciBus;
+ Current->PciData->u.type1.SubordinateBus = (UCHAR) 0xFF;
+ Current->PciData->u.type1.SecondaryStatus = 0xffff;
+ Current->PciData->Status = 0xffff;
+ Current->PciData->Command = 0;
+
+ Current->PciData->u.type1.BridgeControl = PCI_ASSERT_BRIDGE_RESET;
+
+ HalpWritePCIConfig (
+ Current->BusHandler,
+ Current->SlotNumber,
+ Current->PciData,
+ 0,
+ PCI_COMMON_HDR_LENGTH
+ );
+
+ KeStallExecutionProcessor (100);
+
+ Current->PciData->u.type1.BridgeControl = 0;
+ HalpWritePCIConfig (
+ Current->BusHandler,
+ Current->SlotNumber,
+ Current->PciData,
+ 0,
+ PCI_COMMON_HDR_LENGTH
+ );
+
+
+ KeStallExecutionProcessor (100);
+
+ //
+ // Allocate new handler for bus
+ //
+
+ CB.BusHandler = HalpAllocateAndInitPciBusHandler (HwType, *MaxPciBus, FALSE);
+ CB.BusData = (PPCIPBUSDATA) CB.BusHandler->BusData;
+ CB.BusNo = *MaxPciBus;
+ *MaxPciBus += 1;
+
+ //
+ // Add another PCI bus in the registry
+ //
+
+ mnum = 0;
+ for (; ;) {
+ //
+ // Find next available MultiFunctionAdapter key
+ //
+
+ DesiredAccess = KEY_READ | KEY_WRITE;
+ swprintf ((PWCHAR) buffer, L"%s\\%d", rgzMultiFunctionAdapter, mnum);
+ RtlInitUnicodeString (&unicodeString, (PWCHAR) buffer);
+
+ InitializeObjectAttributes( &objectAttributes,
+ &unicodeString,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ (PSECURITY_DESCRIPTOR) NULL
+ );
+
+ status = ZwOpenKey( &handle, DesiredAccess, &objectAttributes);
+ if (!NT_SUCCESS(status)) {
+ break;
+ }
+
+ // already exists, next
+ ZwClose (handle);
+ mnum += 1;
+ }
+
+ ZwCreateKey (&handle,
+ DesiredAccess,
+ &objectAttributes,
+ 0,
+ NULL,
+ REG_OPTION_VOLATILE,
+ &d
+ );
+
+ //
+ // Add needed registry values for this MultifucntionAdapter entry
+ //
+
+ RtlInitUnicodeString (&unicodeString, rgzIdentifier);
+ ZwSetValueKey (handle,
+ &unicodeString,
+ 0L,
+ REG_SZ,
+ L"PCI",
+ sizeof (L"PCI")
+ );
+
+ RtlInitUnicodeString (&unicodeString, rgzConfigurationData);
+ Descriptor = (PCM_FULL_RESOURCE_DESCRIPTOR) buffer;
+ Descriptor->InterfaceType = PCIBus;
+ Descriptor->BusNumber = CB.BusNo;
+ Descriptor->PartialResourceList.Version = 0;
+ Descriptor->PartialResourceList.Revision = 0;
+ Descriptor->PartialResourceList.Count = 0;
+ ZwSetValueKey (handle,
+ &unicodeString,
+ 0L,
+ REG_FULL_RESOURCE_DESCRIPTOR,
+ Descriptor,
+ sizeof (*Descriptor)
+ );
+
+
+ RtlInitUnicodeString (&unicodeString, L"Component Information");
+ Component = (PCONFIGURATION_COMPONENT) buffer;
+ RtlZeroMemory (Component, sizeof (*Component));
+ Component->AffinityMask = 0xffffffff;
+ ZwSetValueKey (handle,
+ &unicodeString,
+ 0L,
+ REG_BINARY,
+ Component,
+ FIELD_OFFSET (CONFIGURATION_COMPONENT, ConfigurationDataLength)
+ );
+
+ ZwClose (handle);
+
+
+ //
+ // Since the BIOS didn't configure this bridge we'll assume that
+ // the PCI interrupts are bridged. (for BIOS configured buses we
+ // assume that the BIOS put the ISA bus IRQ in the InterruptLine value)
+ //
+
+ CB.BusData->Pin2Line = (PciPin2Line) HalpPCIBridgedPin2Line;
+ CB.BusData->Line2Pin = (PciLine2Pin) HalpPCIBridgedLine2Pin;
+ //CB.BusData->GetIrqTable = (PciIrqTable) HalpGetBridgedPCIIrqTable;
+
+ if (Current->BusHandler->GetInterruptVector == HalpGetPCIIntOnISABus) {
+
+ //
+ // The parent bus'es interrupt pin to vector mappings is not
+ // a static function, and is determined by the boot firmware.
+ //
+
+ //CB.BusHandler->GetInterruptVector = (PGETINTERRUPTVECTOR) HalpGetBridgedPCIISAInt;
+
+ // read each device on parent bus
+ 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;
+
+ HalpReadPCIConfig (
+ Current->BusHandler,
+ CB.SlotNumber,
+ CB.PciData,
+ 0,
+ PCI_COMMON_HDR_LENGTH
+ );
+
+ if (CB.PciData->VendorID == PCI_INVALID_VENDORID) {
+ break;
+ }
+
+ if (CB.PciData->u.type0.InterruptPin &&
+ (PCI_CONFIG_TYPE (CB.PciData) == PCI_DEVICE_TYPE ||
+ PCI_CONFIG_TYPE (CB.PciData) == PCI_BRIDGE_TYPE)) {
+
+ // get bios supplied int mapping
+ i = CB.PciData->u.type0.InterruptPin + d % 4;
+ CB.BusData->SwizzleIn[i] = CB.PciData->u.type0.InterruptLine;
+ }
+ }
+ }
+
+ } else {
+ _asm int 3;
+ }
+
+ //
+ // Look at each device on the bus and determine it's resource needs
+ //
+
+ 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;
+
+ HalpReadPCIConfig (
+ CB.BusHandler,
+ CB.SlotNumber,
+ CB.PciData,
+ 0,
+ PCI_COMMON_HDR_LENGTH
+ );
+
+ if (CB.PciData->VendorID == PCI_INVALID_VENDORID) {
+ break;
+ }
+
+ if (IsPciBridge (CB.PciData)) {
+ // oh look - another bridge ...
+ HalpGetPciBridgeNeeds (HwType, MaxPciBus, &CB);
+ continue;
+ }
+
+ if (PCI_CONFIG_TYPE (CB.PciData) != PCI_DEVICE_TYPE) {
+ continue;
+ }
+
+ // found a device - figure out the resources it needs
+ }
+ }
+
+ //
+ // Found all sub-buses set SubordinateBus accordingly
+ //
+
+ Current->PciData->u.type1.SubordinateBus = (UCHAR) *MaxPciBus - 1;
+
+ HalpWritePCIConfig (
+ Current->BusHandler,
+ Current->SlotNumber,
+ Current->PciData,
+ 0,
+ PCI_COMMON_HDR_LENGTH
+ );
+
+
+ //
+ // Set the bridges IO, Memory, and Prefetch Memory windows
+ //
+
+ // For now just pick some numbers & set everyone the same
+ // IO 0x6000 - 0xFFFF
+ // MEM 0x40000000 - 0x4FFFFFFF
+ // PFMEM 0x50000000 - 0x5FFFFFFF
+
+ Current->PciData->u.type1.IOBase = 0x6000 >> 12 << 4;
+ Current->PciData->u.type1.IOLimit = 0xffff >> 12 << 4;
+ Current->PciData->u.type1.MemoryBase = 0x40000000 >> 20 << 4;
+ Current->PciData->u.type1.MemoryLimit = 0x4fffffff >> 20 << 4;
+ Current->PciData->u.type1.PrefetchBase = 0x50000000 >> 20 << 4;
+ Current->PciData->u.type1.PrefetchLimit = 0x5fffffff >> 20 << 4;
+
+ Current->PciData->u.type1.PrefetchBaseUpper32 = 0;
+ Current->PciData->u.type1.PrefetchLimitUpper32 = 0;
+ Current->PciData->u.type1.IOBaseUpper16 = 0;
+ Current->PciData->u.type1.IOLimitUpper16 = 0;
+ Current->PciData->u.type1.BridgeControl =
+ PCI_ENABLE_BRIDGE_ISA;
+
+ HalpWritePCIConfig (
+ Current->BusHandler,
+ Current->SlotNumber,
+ Current->PciData,
+ 0,
+ PCI_COMMON_HDR_LENGTH
+ );
+
+ HalpReadPCIConfig (
+ Current->BusHandler,
+ Current->SlotNumber,
+ Current->PciData,
+ 0,
+ PCI_COMMON_HDR_LENGTH
+ );
+
+ // enable memory & io decodes
+
+ Current->PciData->Command =
+ PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE | PCI_ENABLE_BUS_MASTER;
+
+ HalpWritePCIConfig (
+ Current->BusHandler,
+ Current->SlotNumber,
+ &Current->PciData->Command,
+ FIELD_OFFSET (PCI_COMMON_CONFIG, Command),
+ sizeof (Current->PciData->Command)
+ );
+
+ ExFreePool (buffer);
+}
+
+VOID
+HalpPCIBridgedPin2Line (
+ 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.
+
+ test function particular to dec pci-pci bridge card
+
+--*/
+{
+ PPCIPBUSDATA BusData;
+ ULONG i;
+
+ if (!PciData->u.type0.InterruptPin) {
+ return ;
+ }
+
+ BusData = (PPCIPBUSDATA) BusHandler->BusData;
+
+ //
+ // Convert slot Pin into Bus INTA-D.
+ //
+
+ i = (PciData->u.type0.InterruptPin +
+ SlotNumber.u.bits.DeviceNumber - 1) % 4;
+
+ PciData->u.type0.InterruptLine = BusData->SwizzleIn[i] ^ IRQXOR;
+ PciData->u.type0.InterruptLine = 0x0b ^ IRQXOR;
+}
+
+
+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
+ )
+/*++
+
+ This functions maps the device's InterruptLine to it's
+ device specific InterruptPin value.
+
+ test function particular to dec pci-pci bridge card
+
+--*/
+{
+ PPCIPBUSDATA BusData;
+ ULONG i;
+
+ if (!PciNewData->u.type0.InterruptPin) {
+ return ;
+ }
+
+ BusData = (PPCIPBUSDATA) BusHandler->BusData;
+
+ i = (PciNewData->u.type0.InterruptPin +
+ SlotNumber.u.bits.DeviceNumber - 1) % 4;
+
+ PciNewData->u.type0.InterruptLine = BusData->SwizzleIn[i] ^ IRQXOR;
+ PciNewData->u.type0.InterruptLine = 0x0b ^ IRQXOR;
+}
+
+#endif
diff --git a/private/ntos/nthals/halx86/i386/ixpcibus.c b/private/ntos/nthals/halx86/i386/ixpcibus.c
new file mode 100644
index 000000000..7565c964b
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixpcibus.c
@@ -0,0 +1,2520 @@
+/*++
+
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ ixpcidat.c
+
+Abstract:
+
+ Get/Set bus data routines for the PCI bus
+
+Author:
+
+ Ken Reneris (kenr) 14-June-1994
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "halp.h"
+#include "pci.h"
+#include "pcip.h"
+
+extern WCHAR rgzMultiFunctionAdapter[];
+extern WCHAR rgzConfigurationData[];
+extern WCHAR rgzIdentifier[];
+extern WCHAR rgzPCIIdentifier[];
+
+
+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
+ );
+
+VOID
+HalpPCISynchronizeOrionB0 (
+ IN PBUS_HANDLER BusHandler,
+ IN PCI_SLOT_NUMBER Slot,
+ IN PKIRQL Irql,
+ IN PPCI_TYPE1_CFG_BITS PciCfg1
+ );
+
+VOID
+HalpPCIReleaseSynchronzationOrionB0 (
+ 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} };
+
+extern BOOLEAN HalpDoingCrashDump;
+
+//
+// Orion B0 errata workaround
+//
+
+struct {
+ PBUS_HANDLER Handler;
+ PCI_SLOT_NUMBER Slot;
+} HalpOrionOPB;
+
+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)
+#pragma alloc_text(PAGELK,HalpPCISynchronizeOrionB0)
+#pragma alloc_text(PAGELK,HalpPCIReleaseSynchronzationOrionB0)
+#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, BusNo, f;
+ PBUS_HANDLER BusHandler;
+ PCI_SLOT_NUMBER SlotNumber;
+ PPCI_COMMON_CONFIG PciData;
+ UCHAR iBuffer[PCI_COMMON_HDR_LENGTH];
+ PKEY_VALUE_FULL_INFORMATION ValueInfo;
+ PCM_FULL_RESOURCE_DESCRIPTOR Desc;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR PDesc;
+ ULONG OPBNumber;
+ BOOLEAN OPBA2B0Found, COPBInbPostingEnabled;
+
+ //
+ // 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);
+ PciData = (PPCI_COMMON_CONFIG) iBuffer;
+
+ //
+ // PCIRegInfo describes the system's PCI support as indicated by the BIOS.
+ //
+
+ HwType = PCIRegInfo->HardwareMechanism & 0xf;
+
+ //
+ // 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);
+ }
+
+
+ //
+ // 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);
+
+
+ //
+ // Look for PCI controllers which have known work-arounds, and make
+ // sure they are applied.
+ //
+
+ OPBNumber = 0;
+ OPBA2B0Found = FALSE;
+ COPBInbPostingEnabled = FALSE;
+
+ SlotNumber.u.bits.Reserved = 0;
+ for (BusNo=0; BusNo < PCIRegInfo->NoBuses; BusNo++) {
+ BusHandler = HalpHandlerForBus (PCIBus, BusNo);
+
+ for (d = 0; d < PCI_MAX_DEVICES; d++) {
+ SlotNumber.u.bits.DeviceNumber = d;
+
+ for (f = 0; f < PCI_MAX_FUNCTION; f++) {
+ SlotNumber.u.bits.FunctionNumber = f;
+
+ //
+ // Read PCI configuration information
+ //
+
+ HalpReadPCIConfig (BusHandler, SlotNumber, PciData, 0, PCI_COMMON_HDR_LENGTH);
+
+ //
+ // Check for chips with known work-arounds to apply
+ //
+
+ if (PciData->VendorID == 0x8086 &&
+ PciData->DeviceID == 0x04A3 &&
+ PciData->RevisionID < 0x11) {
+
+ //
+ // 82430 PCMC controller
+ //
+
+ HalpReadPCIConfig (BusHandler, SlotNumber, buffer, 0x53, 2);
+
+ buffer[0] &= ~0x08; // turn off bit 3 register 0x53
+
+ if (PciData->RevisionID == 0x10) { // on rev 0x10, also turn
+ buffer[1] &= ~0x01; // bit 0 register 0x54
+ }
+
+ HalpWritePCIConfig (BusHandler, SlotNumber, buffer, 0x53, 2);
+ }
+
+ if (PciData->VendorID == 0x8086 &&
+ PciData->DeviceID == 0x0484 &&
+ PciData->RevisionID <= 3) {
+
+ //
+ // 82378 ISA bridge & SIO
+ //
+
+ HalpReadPCIConfig (BusHandler, SlotNumber, buffer, 0x41, 1);
+
+ buffer[0] &= ~0x1; // turn off bit 0 register 0x41
+
+ HalpWritePCIConfig (BusHandler, SlotNumber, buffer, 0x41, 1);
+ }
+
+ //
+ // Look for Orion PCI Bridge
+ //
+
+ if (PciData->VendorID == 0x8086 &&
+ PciData->DeviceID == 0x84c4 ) {
+
+ //
+ // 82450 Orion PCI Bridge Workaround
+ // Need a workaround if following conditions are true:
+ // i) 2 OPBs present
+ // ii)There is an A2/B0 step OPB present.
+ // iii) Inbound posting on the compatibility OPB is
+ // enabled.
+ // NOTE: Inbound Posting on the non-compatibility OPB
+ // MUST BE disabled by BIOS
+ //
+
+ OPBNumber += 1;
+
+ if (PciData->RevisionID <= 4) {
+ OPBA2B0Found = TRUE;
+ }
+
+ if (SlotNumber.u.bits.DeviceNumber == (0xc8>>3)) {
+
+ // Found compatibility OPB. Determine if the compatibility
+ // OPB has inbound posting enabled by testing bit 0 of reg 54
+
+ HalpReadPCIConfig (BusHandler, SlotNumber, buffer, 0x54, 2);
+ COPBInbPostingEnabled = (buffer[0] & 0x1) ? TRUE : FALSE;
+
+ } else {
+
+ // The compatibility OPB ALWAYS has a device
+ // number 0xc8. Save the ncOPB slot number
+ // and BusHandler
+
+ HalpOrionOPB.Slot = SlotNumber;
+ HalpOrionOPB.Handler = BusHandler;
+ }
+ }
+ } // next function
+ } // next device
+ } // next bus
+
+ //
+ // Is Orion B0 workaround needed?
+ //
+
+ if (OPBNumber >= 2 && OPBA2B0Found && COPBInbPostingEnabled) {
+
+ //
+ // Replace synchronization functions with Orion specific functions
+ //
+
+ ASSERT (PCIConfigHandler.Synchronize == HalpPCISynchronizeType1);
+ MmLockPagableCodeSection (&HalpPCISynchronizeOrionB0);
+ PCIConfigHandler.Synchronize = HalpPCISynchronizeOrionB0;
+ PCIConfigHandler.ReleaseSynchronzation = HalpPCIReleaseSynchronzationOrionB0;
+ }
+
+#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
+ //
+
+ BusData->MaxDevice = PCI_MAX_DEVICES;
+ BusData->GetIrqRange = (PciIrqRange) HalpGetISAFixedPCIIrq;
+
+ RtlInitializeBitMap (&BusData->DeviceConfigured,
+ BusData->ConfiguredBits, 256);
+
+ switch (HwType) {
+ case 1:
+ //
+ // Initialize access port information for Type1 handlers
+ //
+
+ RtlCopyMemory (&PCIConfigHandler,
+ &PCIConfigHandlerType1,
+ sizeof (PCIConfigHandler));
+
+ BusData->Config.Type1.Address = PCI_TYPE1_ADDR_PORT;
+ BusData->Config.Type1.Data = PCI_TYPE1_DATA_PORT;
+ break;
+
+ case 2:
+ //
+ // Initialize access port information for Type2 handlers
+ //
+
+ RtlCopyMemory (&PCIConfigHandler,
+ &PCIConfigHandlerType2,
+ sizeof (PCIConfigHandler));
+
+ BusData->Config.Type2.CSE = PCI_TYPE2_CSE_PORT;
+ BusData->Config.Type2.Forward = PCI_TYPE2_FORWARD_PORT;
+ BusData->Config.Type2.Base = PCI_TYPE2_ADDRESS_BASE;
+
+ //
+ // Early PCI machines didn't decode the last bit of
+ // the device id. Shrink type 2 support max device.
+ //
+ BusData->MaxDevice = 0x10;
+
+ 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) {
+ 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) &&
+ PCI_CONFIG_TYPE (PciData) == PCI_DEVICE_TYPE) {
+
+ 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 DBG
+ 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");
+ }
+#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
+ )
+{
+ if (!HalpValidPCISlot (BusHandler, Slot)) {
+ //
+ // Invalid SlotID return no data
+ //
+
+ RtlFillMemory (Buffer, Length, (UCHAR) -1);
+ return ;
+ }
+
+ 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 = 0;
+ PciCfg1->u.bits.BusNumber = BusHandler->BusNumber;
+ PciCfg1->u.bits.DeviceNumber = Slot.u.bits.DeviceNumber;
+ PciCfg1->u.bits.FunctionNumber = Slot.u.bits.FunctionNumber;
+ PciCfg1->u.bits.Enable = TRUE;
+
+ //
+ // Synchronize with PCI type1 config space
+ //
+
+ if (!HalpDoingCrashDump) {
+ *Irql = KfRaiseIrql (HIGH_LEVEL);
+ KiAcquireSpinLock (&HalpPCIConfigLock);
+ } else {
+ *Irql = HIGH_LEVEL;
+ }
+}
+
+VOID
+HalpPCIReleaseSynchronzationType1 (
+ IN PBUS_HANDLER BusHandler,
+ IN KIRQL Irql
+ )
+{
+ PCI_TYPE1_CFG_BITS PciCfg1;
+ PPCIPBUSDATA BusData;
+
+ //
+ // Disable PCI configuration space
+ //
+
+ PciCfg1.u.AsULONG = 0;
+ BusData = (PPCIPBUSDATA) BusHandler->BusData;
+ WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1.u.AsULONG);
+
+ //
+ // Release spinlock
+ //
+
+ if (!HalpDoingCrashDump) {
+ KiReleaseSpinLock (&HalpPCIConfigLock);
+ KfLowerIrql (Irql);
+ }
+}
+
+
+VOID
+HalpPCISynchronizeOrionB0 (
+ IN PBUS_HANDLER BusHandler,
+ IN PCI_SLOT_NUMBER Slot,
+ IN PKIRQL Irql,
+ IN PPCI_TYPE1_CFG_BITS PciCfg1
+ )
+{
+ PCI_TYPE1_CFG_BITS Cfg1;
+ union {
+ ULONG dword;
+ USHORT word;
+ UCHAR byte[4];
+ } Buffer;
+
+ //
+ // First perform normal type 1 synchronization
+ //
+
+ HalpPCISynchronizeType1 (BusHandler, Slot, Irql, PciCfg1);
+
+ //
+ // Apply Orion B0 workaround
+ //
+
+ Cfg1.u.AsULONG=0;
+ Cfg1.u.bits.BusNumber = HalpOrionOPB.Handler->BusNumber;
+ Cfg1.u.bits.DeviceNumber = HalpOrionOPB.Slot.u.bits.DeviceNumber;
+ Cfg1.u.bits.FunctionNumber = HalpOrionOPB.Slot.u.bits.FunctionNumber;
+ Cfg1.u.bits.Enable = TRUE;
+
+ //
+ // Read OPB until we get back the expected Vendor ID and device ID
+ //
+
+ do {
+ HalpPCIReadUlongType1 (HalpOrionOPB.Handler->BusData, &Cfg1, Buffer.byte, 0);
+ } while (Buffer.dword != 0x84c48086);
+
+ //
+ // The bug is that the config read will return whatever value you
+ // happened to read last. Read register 0x54 till we don't read the
+ // last value read any more(Vendor ID/Device ID).
+ //
+
+ do {
+ HalpPCIReadUshortType1 (HalpOrionOPB.Handler->BusData, &Cfg1, Buffer.byte, 0x54);
+ } while (Buffer.word == 0x8086);
+
+ //
+ // Disable inbound posting by clearing bit 0 of register 0x54
+ //
+
+ Buffer.word &= ~0x1;
+ HalpPCIWriteUshortType1 (HalpOrionOPB.Handler->BusData, &Cfg1, Buffer.byte, 0x54);
+}
+
+VOID
+HalpPCIReleaseSynchronzationOrionB0 (
+ IN PBUS_HANDLER BusHandler,
+ IN KIRQL Irql
+ )
+{
+
+ PCI_TYPE1_CFG_BITS PciCfg1;
+ PPCIPBUSDATA BusData;
+ union {
+ ULONG dword;
+ USHORT word;
+ UCHAR byte[4];
+ } Buffer;
+
+ PciCfg1.u.AsULONG=0;
+ PciCfg1.u.bits.BusNumber = HalpOrionOPB.Handler->BusNumber;
+ PciCfg1.u.bits.DeviceNumber = HalpOrionOPB.Slot.u.bits.DeviceNumber;
+ PciCfg1.u.bits.FunctionNumber = HalpOrionOPB.Slot.u.bits.FunctionNumber;
+ PciCfg1.u.bits.Enable = TRUE;
+
+ HalpPCIReadUshortType1 (HalpOrionOPB.Handler->BusData, &PciCfg1, Buffer.byte, 0x54);
+
+
+ //
+ // Enable Inbound posting by setting bit 0 of register 0x54 of ncOPB
+ //
+
+ Buffer.word |= 0x1;
+ HalpPCIWriteUshortType1 (HalpOrionOPB.Handler->BusData, &PciCfg1, Buffer.byte, 0x54);
+
+ //
+ // Complete type 1 synchronization
+ //
+
+ HalpPCIReleaseSynchronzationType1 (BusHandler, 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);
+ WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
+ *Buffer = READ_PORT_UCHAR ((PUCHAR) (BusData->Config.Type1.Data + 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);
+ WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
+ *((PUSHORT) Buffer) = READ_PORT_USHORT ((PUSHORT) (BusData->Config.Type1.Data + 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);
+ WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
+ *((PULONG) Buffer) = READ_PORT_ULONG ((PULONG) BusData->Config.Type1.Data);
+ 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_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
+ WRITE_PORT_UCHAR ((PUCHAR) (BusData->Config.Type1.Data + 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_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
+ WRITE_PORT_USHORT ((PUSHORT) (BusData->Config.Type1.Data + 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 (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
+ WRITE_PORT_ULONG ((PULONG) BusData->Config.Type1.Data, *((PULONG) Buffer));
+ return sizeof (ULONG);
+}
+
+
+VOID HalpPCISynchronizeType2 (
+ IN PBUS_HANDLER BusHandler,
+ IN PCI_SLOT_NUMBER Slot,
+ IN PKIRQL Irql,
+ IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr
+ )
+{
+ PCI_TYPE2_CSE_BITS PciCfg2Cse;
+ PPCIPBUSDATA BusData;
+
+ BusData = (PPCIPBUSDATA) BusHandler->BusData;
+
+ //
+ // Initialize Cfg2Addr
+ //
+
+ PciCfg2Addr->u.AsUSHORT = 0;
+ PciCfg2Addr->u.bits.Agent = (USHORT) Slot.u.bits.DeviceNumber;
+ PciCfg2Addr->u.bits.AddressBase = (USHORT) BusData->Config.Type2.Base;
+
+ //
+ // Synchronize with type2 config space - type2 config space
+ // remaps 4K of IO space, so we can not allow other I/Os to occur
+ // while using type2 config space.
+ //
+
+ HalpPCIAcquireType2Lock (&HalpPCIConfigLock, Irql);
+
+ PciCfg2Cse.u.AsUCHAR = 0;
+ PciCfg2Cse.u.bits.Enable = TRUE;
+ PciCfg2Cse.u.bits.FunctionNumber = (UCHAR) Slot.u.bits.FunctionNumber;
+ PciCfg2Cse.u.bits.Key = 0xff;
+
+ //
+ // Select bus & enable type 2 configuration space
+ //
+
+ WRITE_PORT_UCHAR (BusData->Config.Type2.Forward, (UCHAR) BusHandler->BusNumber);
+ WRITE_PORT_UCHAR (BusData->Config.Type2.CSE, PciCfg2Cse.u.AsUCHAR);
+}
+
+
+VOID HalpPCIReleaseSynchronzationType2 (
+ IN PBUS_HANDLER BusHandler,
+ IN KIRQL Irql
+ )
+{
+ PCI_TYPE2_CSE_BITS PciCfg2Cse;
+ PPCIPBUSDATA BusData;
+
+ //
+ // disable PCI configuration space
+ //
+
+ BusData = (PPCIPBUSDATA) BusHandler->BusData;
+
+ PciCfg2Cse.u.AsUCHAR = 0;
+ WRITE_PORT_UCHAR (BusData->Config.Type2.CSE, PciCfg2Cse.u.AsUCHAR);
+ WRITE_PORT_UCHAR (BusData->Config.Type2.Forward, (UCHAR) 0);
+
+ //
+ // Restore interrupts, release spinlock
+ //
+
+ HalpPCIReleaseType2Lock (&HalpPCIConfigLock, Irql);
+}
+
+
+ULONG
+HalpPCIReadUcharType2 (
+ IN PPCIPBUSDATA BusData,
+ IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ )
+{
+ PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
+ *Buffer = READ_PORT_UCHAR ((PUCHAR) PciCfg2Addr->u.AsUSHORT);
+ return sizeof (UCHAR);
+}
+
+ULONG
+HalpPCIReadUshortType2 (
+ IN PPCIPBUSDATA BusData,
+ IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ )
+{
+ PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
+ *((PUSHORT) Buffer) = READ_PORT_USHORT ((PUSHORT) PciCfg2Addr->u.AsUSHORT);
+ return sizeof (USHORT);
+}
+
+ULONG
+HalpPCIReadUlongType2 (
+ IN PPCIPBUSDATA BusData,
+ IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ )
+{
+ PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
+ *((PULONG) Buffer) = READ_PORT_ULONG ((PULONG) PciCfg2Addr->u.AsUSHORT);
+ return sizeof(ULONG);
+}
+
+
+ULONG
+HalpPCIWriteUcharType2 (
+ IN PPCIPBUSDATA BusData,
+ IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ )
+{
+ PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
+ WRITE_PORT_UCHAR ((PUCHAR) PciCfg2Addr->u.AsUSHORT, *Buffer);
+ return sizeof (UCHAR);
+}
+
+ULONG
+HalpPCIWriteUshortType2 (
+ IN PPCIPBUSDATA BusData,
+ IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ )
+{
+ PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
+ WRITE_PORT_USHORT ((PUSHORT) PciCfg2Addr->u.AsUSHORT, *((PUSHORT) Buffer));
+ return sizeof (USHORT);
+}
+
+ULONG
+HalpPCIWriteUlongType2 (
+ IN PPCIPBUSDATA BusData,
+ IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ )
+{
+ PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
+ WRITE_PORT_ULONG ((PULONG) PciCfg2Addr->u.AsUSHORT, *((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, RequestedInterrupt;
+
+
+ *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;
+ }
+
+ //
+ // For now since there's not PnP support in the OS, if the BIOS hasn't
+ // enable a VGA device don't allow it to get enabled via this interface.
+ //
+
+ if ( (PciData->BaseClass == 0 && PciData->SubClass == 1) ||
+ (PciData->BaseClass == 3 && PciData->SubClass == 0)) {
+
+ if ((PciData->Command & (PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE)) == 0) {
+ ExFreePool (WorkingPool);
+ return STATUS_DEVICE_NOT_CONNECTED;
+ }
+ }
+
+ //
+ // 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;
+ }
+
+ 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
+ //
+
+ RequestedInterrupt = FALSE;
+ if (PciData->u.type0.InterruptPin &&
+ PciData->u.type0.InterruptLine != (0 ^ IRQXOR) &&
+ PciData->u.type0.InterruptLine != (0xFF ^ IRQXOR)) {
+
+ RequestedInterrupt = TRUE;
+ 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
+ //
+
+ // Clear ROM reserved bits
+
+ *BaseAddress[RomIndex] &= ~0x7FF;
+
+ 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 (!Is64BitBaseAddress(i) &&
+ 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;
+ }
+ }
+
+ CompleteList->List[0].Count++;
+ Descriptor++;
+
+
+ if (Is64BitBaseAddress(i)) {
+ // skip upper half of 64 bit address since this processor
+ // only supports 32 bits of address space
+ j++;
+ }
+ }
+ }
+
+ 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 (RequestedInterrupt) {
+ 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
+ //
+
+ for (j=0; j < NoBaseAddress; j++) {
+ i = *BaseAddress[j];
+ if (i) {
+ if (i & PCI_ADDRESS_IO_SPACE) {
+ *BaseAddress[j] = CmDescriptor->u.Port.Start.LowPart;
+ } else {
+ *BaseAddress[j] = CmDescriptor->u.Memory.Start.LowPart;
+ }
+ CmDescriptor++;
+ }
+
+ if (Is64BitBaseAddress(i)) {
+ // skip upper 32 bits
+ j++;
+ }
+ }
+
+ //
+ // Turn off decodes, then set new addresses
+ //
+
+ 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 (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, and BUS_MASTER decodes
+ // (use HalSetBusData since valid settings now set)
+ //
+
+ PciData->Command |= PCI_ENABLE_IO_SPACE |
+ PCI_ENABLE_MEMORY_SPACE |
+ PCI_ENABLE_BUS_MASTER;
+
+ 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/halx86/i386/ixpciint.c b/private/ntos/nthals/halx86/i386/ixpciint.c
new file mode 100644
index 000000000..896e141f7
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixpciint.c
@@ -0,0 +1,458 @@
+/*++
+
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ ixpciint.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
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "halp.h"
+#include "pci.h"
+#include "pcip.h"
+
+ULONG PciIsaIrq;
+ULONG HalpEisaELCR;
+BOOLEAN HalpDoingCrashDump;
+BOOLEAN HalpPciLockSettings;
+
+
+#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 (
+#ifndef MCA
+ Isa, 0,
+#else
+ MicroChannel, 0,
+#endif
+ BusInterruptLevel ^ IRQXOR,
+ 0,
+ 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.
+
+ On a DBG build we adjust InterruptLine just to ensure driver's
+ don't connect to it without translating it on the PCI bus.
+
+--*/
+{
+ if (!PciData->u.type0.InterruptPin) {
+ return ;
+ }
+
+ //
+ // Set vector as a level vector. (note: this code assumes the
+ // irq is static and does not move).
+ //
+
+ if (PciData->u.type0.InterruptLine >= 1 &&
+ PciData->u.type0.InterruptLine <= 15) {
+
+ //
+ // If this bit was on the in the PIC ELCR register,
+ // then mark it in PciIsaIrq. (for use in hal.dll,
+ // such that we can assume the interrupt controller
+ // has been properly marked as a level interrupt for
+ // this IRQ. Other hals probabily don't care.)
+ //
+
+ PciIsaIrq |= HalpEisaELCR & (1 << PciData->u.type0.InterruptLine);
+ }
+
+ //
+ // On a PC there's no Slot/Pin/Line mapping which needs to
+ // be done.
+ //
+
+ PciData->u.type0.InterruptLine ^= IRQXOR;
+}
+
+
+
+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.
+
+--*/
+{
+ if (!PciNewData->u.type0.InterruptPin) {
+ return ;
+ }
+
+ PciNewData->u.type0.InterruptLine ^= IRQXOR;
+
+#if DBG
+ if (PciNewData->u.type0.InterruptLine != PciOldData->u.type0.InterruptLine ||
+ PciNewData->u.type0.InterruptPin != PciOldData->u.type0.InterruptPin) {
+ DbgPrint ("HalpPCILine2Pin: System does not support changing the PCI device interrupt routing\n");
+ DbgBreakPoint ();
+ }
+#endif
+}
+
+#if !defined(SUBCLASSPCI)
+
+VOID
+HalpPCIAcquireType2Lock (
+ PKSPIN_LOCK SpinLock,
+ PKIRQL Irql
+ )
+{
+ if (!HalpDoingCrashDump) {
+ *Irql = KfRaiseIrql (HIGH_LEVEL);
+ KiAcquireSpinLock (SpinLock);
+ } else {
+ *Irql = HIGH_LEVEL;
+ }
+}
+
+
+VOID
+HalpPCIReleaseType2Lock (
+ PKSPIN_LOCK SpinLock,
+ KIRQL Irql
+ )
+{
+ if (!HalpDoingCrashDump) {
+ KiReleaseSpinLock (SpinLock);
+ KfLowerIrql (Irql);
+ }
+}
+
+#endif
+
+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;
+ PSUPPORTED_RANGE Range;
+ PSUPPORTED_RANGES SupportedRanges;
+ PPCI_COMMON_CONFIG PciData, PciOrigData;
+ UCHAR buffer[PCI_COMMON_HDR_LENGTH];
+ UCHAR buffer2[PCI_COMMON_HDR_LENGTH];
+ BOOLEAN UseBusRanges;
+ ULONG i, j, RomIndex, length, ebit;
+ ULONG Base[PCI_TYPE0_ADDRESSES + 1];
+ PULONG BaseAddress[PCI_TYPE0_ADDRESSES + 1];
+
+
+ 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;
+ }
+
+ SupportedRanges = NULL;
+ UseBusRanges = TRUE;
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ if (HalpPciLockSettings) {
+
+ PciData = (PPCI_COMMON_CONFIG) buffer;
+ PciOrigData = (PPCI_COMMON_CONFIG) buffer2;
+ HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
+
+ //
+ // If this is a device, and it current has its decodes enabled,
+ // then use the currently programmed ranges only
+ //
+
+ if (PCI_CONFIG_TYPE(PciData) == 0 &&
+ (PciData->Command & (PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE))) {
+
+ //
+ // Save current settings
+ //
+
+ RtlMoveMemory (PciOrigData, PciData, PCI_COMMON_HDR_LENGTH);
+
+
+ for (j=0; j < PCI_TYPE0_ADDRESSES; j++) {
+ BaseAddress[j] = &PciData->u.type0.BaseAddresses[j];
+ }
+ BaseAddress[j] = &PciData->u.type0.ROMBaseAddress;
+ RomIndex = j;
+
+ //
+ // Write all one-bits to determine lengths for each address
+ //
+
+ for (j=0; j < PCI_TYPE0_ADDRESSES + 1; j++) {
+ Base[j] = *BaseAddress[j];
+ *BaseAddress[j] = 0xFFFFFFFF;
+ }
+
+ 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);
+
+ //
+ // restore original settings
+ //
+
+ 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)
+ );
+
+ //
+ // Build a memory & io range list of just the ranges already
+ // programmed into the device
+ //
+
+ UseBusRanges = FALSE;
+ SupportedRanges = HalpAllocateNewRangeList();
+ if (!SupportedRanges) {
+ goto CleanUp;
+ }
+
+ *BaseAddress[RomIndex] &= ~PCI_ADDRESS_IO_SPACE;
+ for (j=0; j < PCI_TYPE0_ADDRESSES + 1; j++) {
+
+ i = *BaseAddress[j];
+
+ if (i & PCI_ADDRESS_IO_SPACE) {
+ length = 1 << 2;
+ Range = &SupportedRanges->IO;
+ ebit = PCI_ENABLE_IO_SPACE;
+
+ } else {
+ length = 1 << 4;
+ Range = &SupportedRanges->Memory;
+ ebit = PCI_ENABLE_MEMORY_SPACE;
+
+ if (i & PCI_ADDRESS_MEMORY_PREFETCHABLE) {
+ Range = &SupportedRanges->PrefetchMemory;
+ }
+ }
+
+ Base[j] &= ~(length-1);
+ while (!(i & length) && length) {
+ length <<= 1;
+ }
+
+ if (j == RomIndex &&
+ !(PciOrigData->u.type0.ROMBaseAddress & PCI_ROMADDRESS_ENABLED)) {
+
+ // range not enabled, don't use it
+ length = 0;
+ }
+
+ if (length) {
+ if (!(PciOrigData->Command & ebit)) {
+ // range not enabled, don't use preprogrammed values
+ UseBusRanges = TRUE;
+ }
+
+ if (Range->Limit >= Range->Base) {
+ Range->Next = ExAllocatePool (PagedPool, sizeof (SUPPORTED_RANGE));
+ Range = Range->Next;
+ if (!Range) {
+ goto CleanUp;
+ }
+
+ Range->Next = NULL;
+ }
+
+ Range->Base = Base[j];
+ Range->Limit = Base[j] + length - 1;
+ }
+
+ if (Is64BitBaseAddress(i)) {
+ // skip upper half of 64 bit address since this processor
+ // only supports 32 bits of address space
+ j++;
+ }
+ }
+ }
+ }
+
+ //
+ // Adjust resources
+ //
+
+ Status = HaliAdjustResourceListRange (
+ UseBusRanges ? BusHandler->BusAddresses : SupportedRanges,
+ Interrupt,
+ pResourceList
+ );
+
+CleanUp:
+ if (SupportedRanges) {
+ HalpFreeRangeList (SupportedRanges);
+ }
+
+ 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 ^ IRQXOR) ||
+ PciData->u.type0.InterruptLine == (0xFF ^ IRQXOR)) {
+
+#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/halx86/i386/ixphwsup.c b/private/ntos/nthals/halx86/i386/ixphwsup.c
new file mode 100644
index 000000000..ce04cdbfb
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixphwsup.c
@@ -0,0 +1,535 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ixphwsup.c
+
+Abstract:
+
+ This module contains the HalpXxx routines for the NT I/O system that
+ are hardware dependent. Were these routines not hardware dependent,
+ they would normally reside in the internal.c module.
+
+Author:
+
+ Darryl E. Havens (darrylh) 11-Apr-1990
+
+Environment:
+
+ Kernel mode, local to I/O system
+
+Revision History:
+
+
+--*/
+
+#include "halp.h"
+#if MCA
+
+#include "mca.h"
+
+#else
+
+#include "eisa.h"
+
+#endif
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE,HalpAllocateAdapter)
+#pragma alloc_text(PAGELK,HalpGrowMapBuffers)
+#endif
+
+
+//
+// Some devices require a phyicially contiguous data buffers for DMA transfers.
+// Map registers are used give the appearance that all data buffers are
+// contiguous. In order to pool all of the map registers a master
+// adapter object is used. This object is allocated and saved internal to this
+// file. It contains a bit map for allocation of the registers and a queue
+// for requests which are waiting for more map registers. This object is
+// allocated during the first request to allocate an adapter which requires
+// map registers.
+//
+
+PADAPTER_OBJECT MasterAdapterObject;
+
+BOOLEAN LessThan16Mb;
+BOOLEAN HalpEisaDma;
+//
+// Map buffer prameters. These are initialized in HalInitSystem
+//
+
+PHYSICAL_ADDRESS HalpMapBufferPhysicalAddress;
+ULONG HalpMapBufferSize;
+
+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.
+
+ Caller owns the HalpNewAdapter event
+
+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;
+ PHYSICAL_ADDRESS physicalAddress;
+ KIRQL Irql;
+ PVOID CodeLockHandle;
+
+ PAGED_CODE();
+
+ 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.
+ // Serialize with master adapter object
+ //
+
+ CodeLockHandle = MmLockPagableCodeSection (&HalpGrowMapBuffers);
+ Irql = KfAcquireSpinLock( &AdapterObject->SpinLock );
+
+ TranslationEntry = ((PTRANSLATION_ENTRY) AdapterObject->MapRegisterBase) +
+ AdapterObject->NumberOfMapRegisters;
+
+ for (i = 0; (LONG) i < NumberOfPages; i++) {
+
+ //
+ // Make sure the perivous entry is physically contiguous with the next
+ // entry and that a 64K physical bountry is not crossed unless this
+ // is an Eisa system.
+ //
+
+ if (TranslationEntry != AdapterObject->MapRegisterBase &&
+ (((TranslationEntry - 1)->PhysicalAddress + PAGE_SIZE) !=
+ MapBufferPhysicalAddress || (!HalpEisaDma &&
+ ((TranslationEntry - 1)->PhysicalAddress & ~0x0ffff) !=
+ (MapBufferPhysicalAddress & ~0x0ffff)))) {
+
+ //
+ // An entry needs to be skipped in the table. This entry will
+ // remain marked as allocated so that no allocation of map
+ // registers will cross this bountry.
+ //
+
+ TranslationEntry++;
+ AdapterObject->NumberOfMapRegisters++;
+ }
+
+ //
+ // Clear the bits where the memory has been allocated.
+ //
+
+ RtlClearBits(
+ AdapterObject->MapRegisters,
+ TranslationEntry - (PTRANSLATION_ENTRY)
+ AdapterObject->MapRegisterBase,
+ 1
+ );
+
+ TranslationEntry->VirtualAddress = MapBufferVirtualAddress;
+ TranslationEntry->PhysicalAddress = MapBufferPhysicalAddress;
+ TranslationEntry++;
+ (PCCHAR) MapBufferVirtualAddress += PAGE_SIZE;
+ MapBufferPhysicalAddress += PAGE_SIZE;
+
+ }
+
+ //
+ // Remember the number of pages that where allocated.
+ //
+
+ AdapterObject->NumberOfMapRegisters += NumberOfPages;
+
+ //
+ // Release master adapter object
+ //
+
+ KfReleaseSpinLock( &AdapterObject->SpinLock, Irql );
+ MmUnlockPagableImageSection (CodeLockHandle);
+ return(TRUE);
+}
+
+PADAPTER_OBJECT
+HalpAllocateAdapter(
+ IN ULONG MapRegistersPerChannel,
+ IN PVOID AdapterBaseVa,
+ IN PVOID ChannelNumber
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and initializes an adapter object to represent an
+ adapter or a DMA controller on the system. If no map registers are required
+ then a standalone adapter object is allocated with no master adapter.
+
+ If map registers are required, then a master adapter object is used to
+ allocate the map registers. For Isa systems these registers are really
+ phyically contiguous memory pages.
+
+ Caller owns the HalpNewAdapter event
+
+
+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);
+
+ PAGED_CODE();
+
+ //
+ // Initalize the master adapter if necessary.
+ //
+
+ if (MasterAdapterObject == NULL && AdapterBaseVa != (PVOID) -1 &&
+ MapRegistersPerChannel) {
+
+ MasterAdapterObject = HalpAllocateAdapter(
+ MapRegistersPerChannel,
+ (PVOID) -1,
+ NULL
+ );
+
+ //
+ // If we could not allocate the master adapter then give up.
+ //
+
+ if (MasterAdapterObject == NULL) {
+ return(NULL);
+ }
+ }
+
+ //
+ // Begin by initializing the object attributes structure to be used when
+ // creating the adapter object.
+ //
+
+ InitializeObjectAttributes( &ObjectAttributes,
+ NULL,
+ OBJ_PERMANENT,
+ (HANDLE) NULL,
+ (PSECURITY_DESCRIPTOR) NULL
+ );
+
+ //
+ // Determine the size of the adapter object. If this is the master object
+ // then allocate space for the register bit map; otherwise, just allocate
+ // an adapter object.
+ //
+ if (AdapterBaseVa == (PVOID) -1) {
+
+ //
+ // Allocate a bit map large enough MAXIMUM_MAP_BUFFER_SIZE / PAGE_SIZE
+ // of map register buffers.
+ //
+
+ BitmapSize = (((sizeof( RTL_BITMAP ) +
+ (( MAXIMUM_MAP_BUFFER_SIZE / PAGE_SIZE ) + 7 >> 3)) + 3) & ~3);
+
+ Size = sizeof( ADAPTER_OBJECT ) + BitmapSize;
+
+ } else {
+
+ Size = sizeof( ADAPTER_OBJECT );
+
+ }
+
+ //
+ // Now create the adapter object.
+ //
+
+ Status = ObCreateObject( KernelMode,
+ *IoAdapterObjectType,
+ &ObjectAttributes,
+ KernelMode,
+ (PVOID) NULL,
+ Size,
+ 0,
+ 0,
+ (PVOID *)&AdapterObject );
+
+ //
+ // Reference the object.
+ //
+
+ if (NT_SUCCESS(Status)) {
+
+ Status = ObReferenceObjectByPointer(
+ AdapterObject,
+ FILE_READ_DATA | FILE_WRITE_DATA,
+ *IoAdapterObjectType,
+ KernelMode
+ );
+
+ }
+
+ //
+ // If the adapter object was successfully created, then attempt to insert
+ // it into the the object table.
+ //
+
+ if (NT_SUCCESS( Status )) {
+
+ RtlZeroMemory (AdapterObject, sizeof (ADAPTER_OBJECT));
+
+ Status = ObInsertObject( AdapterObject,
+ NULL,
+ FILE_READ_DATA | FILE_WRITE_DATA,
+ 0,
+ (PVOID *) NULL,
+ &Handle );
+
+ if (NT_SUCCESS( Status )) {
+
+ ZwClose( Handle );
+
+ //
+ // Initialize the adapter object itself.
+ //
+
+ AdapterObject->Type = IO_TYPE_ADAPTER;
+ AdapterObject->Size = (USHORT) Size;
+ AdapterObject->MapRegistersPerChannel = 1;
+ AdapterObject->AdapterBaseVa = AdapterBaseVa;
+
+ if (MapRegistersPerChannel) {
+
+ AdapterObject->MasterAdapter = MasterAdapterObject;
+
+ } else {
+
+ AdapterObject->MasterAdapter = NULL;
+
+ }
+
+ //
+ // Initialize the channel wait queue for this
+ // adapter.
+ //
+
+ KeInitializeDeviceQueue( &AdapterObject->ChannelWaitQueue );
+
+ //
+ // If this is the MasterAdatper then initialize the register bit map,
+ // AdapterQueue and the spin lock.
+ //
+
+ if ( AdapterBaseVa == (PVOID) -1 ) {
+
+ KeInitializeSpinLock( &AdapterObject->SpinLock );
+
+ InitializeListHead( &AdapterObject->AdapterQueue );
+
+ AdapterObject->MapRegisters = (PVOID) ( AdapterObject + 1);
+
+ RtlInitializeBitMap( AdapterObject->MapRegisters,
+ (PULONG) (((PCHAR) (AdapterObject->MapRegisters)) + sizeof( RTL_BITMAP )),
+ ( MAXIMUM_MAP_BUFFER_SIZE / PAGE_SIZE )
+ );
+ //
+ // Set all the bits in the memory to indicate that memory
+ // has not been allocated for the map buffers
+ //
+
+ RtlSetAllBits( AdapterObject->MapRegisters );
+ AdapterObject->NumberOfMapRegisters = 0;
+ AdapterObject->CommittedMapRegisters = 0;
+
+ //
+ // ALlocate the memory map registers.
+ //
+
+ AdapterObject->MapRegisterBase = ExAllocatePool(
+ NonPagedPool,
+ (MAXIMUM_MAP_BUFFER_SIZE / PAGE_SIZE) *
+ sizeof(TRANSLATION_ENTRY)
+ );
+
+ if (AdapterObject->MapRegisterBase == NULL) {
+
+ ObDereferenceObject( AdapterObject );
+ AdapterObject = NULL;
+ return(NULL);
+
+ }
+
+ //
+ // Zero the map registers.
+ //
+
+ RtlZeroMemory(
+ AdapterObject->MapRegisterBase,
+ (MAXIMUM_MAP_BUFFER_SIZE / PAGE_SIZE) *
+ sizeof(TRANSLATION_ENTRY)
+ );
+
+ if (!HalpGrowMapBuffers(AdapterObject, INITIAL_MAP_BUFFER_SMALL_SIZE))
+ {
+
+ //
+ // If no map registers could be allocated then free the
+ // object.
+ //
+
+ ObDereferenceObject( AdapterObject );
+ AdapterObject = NULL;
+ return(NULL);
+
+ }
+ }
+
+ } else {
+
+ //
+ // An error was incurred for some reason. Set the return value
+ // to NULL.
+ //
+
+ AdapterObject = (PADAPTER_OBJECT) NULL;
+ }
+ } else {
+
+ AdapterObject = (PADAPTER_OBJECT) NULL;
+
+ }
+
+
+ return AdapterObject;
+
+}
diff --git a/private/ntos/nthals/halx86/i386/ixproc.c b/private/ntos/nthals/halx86/i386/ixproc.c
new file mode 100644
index 000000000..c9782e366
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixproc.c
@@ -0,0 +1,160 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ixsproc.c
+
+Abstract:
+
+ Stub functions for UP hals.
+
+Author:
+
+ Ken Reneris (kenr) 22-Jan-1991
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+
+UCHAR HalName[] = "PC Compatible Eisa/Isa HAL";
+
+BOOLEAN
+HalpInitMP (
+ IN ULONG Phase,
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ );
+
+VOID
+HalpMcaInit (
+ VOID
+ );
+
+VOID HalpInitOtherBuses (VOID);
+VOID HalpInitializePciBus (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
+ )
+{
+ // do nothing
+ return TRUE;
+}
+
+
+VOID
+HalpResetAllProcessors (
+ VOID
+ )
+{
+ // Just return, that will invoke the standard PC reboot code
+}
+
+
+BOOLEAN
+HalStartNextProcessor (
+ IN PLOADER_PARAMETER_BLOCK pLoaderBlock,
+ IN PKPROCESSOR_STATE pProcessorState
+ )
+{
+ // no other processors
+ return FALSE;
+}
+
+BOOLEAN
+HalAllProcessorsStarted (
+ VOID
+ )
+{
+ // do nothing
+ return TRUE;
+}
+
+
+VOID
+HalReportResourceUsage (
+ VOID
+ )
+{
+ INTERFACE_TYPE interfacetype;
+ ANSI_STRING AHalName;
+ UNICODE_STRING UHalName;
+
+ HalInitSystemPhase2 ();
+
+ switch (HalpBusType) {
+ case MACHINE_TYPE_ISA: interfacetype = Isa; break;
+ case MACHINE_TYPE_EISA: interfacetype = Eisa; break;
+ case MACHINE_TYPE_MCA: interfacetype = MicroChannel; break;
+ default: interfacetype = Internal; break;
+ }
+
+ RtlInitAnsiString (&AHalName, HalName);
+ RtlAnsiStringToUnicodeString (&UHalName, &AHalName, TRUE);
+ HalpReportResourceUsage (
+ &UHalName, // descriptive name
+ interfacetype // device space interface type
+ );
+
+ RtlFreeUnicodeString (&UHalName);
+
+ //
+ // Turn on MCA support if present
+ //
+
+ HalpMcaInit();
+
+ //
+ // Registry is now intialized, see if there are any PCI buses
+ //
+
+ HalpInitializePciBus ();
+
+#if 0
+ //
+ // Display all buses & ranges
+ //
+
+ HalpDisplayAllBusRanges ();
+#endif
+}
+
+
+VOID
+HalpInitOtherBuses (
+ VOID
+ )
+{
+ // no other internal buses supported
+}
+
+ULONG
+FASTCALL
+HalSystemVectorDispatchEntry (
+ IN ULONG Vector,
+ OUT PKINTERRUPT_ROUTINE **FlatDispatch,
+ OUT PKINTERRUPT_ROUTINE *NoConnection
+ )
+{
+ return FALSE;
+}
diff --git a/private/ntos/nthals/halx86/i386/ixprofil.asm b/private/ntos/nthals/halx86/i386/ixprofil.asm
new file mode 100644
index 000000000..5758de5d9
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixprofil.asm
@@ -0,0 +1,437 @@
+
+ title "Interval Clock Interrupt"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; ixprofile.asm
+;
+; Abstract:
+;
+; This module implements the code necessary to initialize,
+; field and process the profile interrupt.
+;
+; Author:
+;
+; Shie-Lin Tzong (shielint) 12-Jan-1990
+;
+; Environment:
+;
+; Kernel mode only.
+;
+; Revision History:
+;
+; bryanwi 20-Sep-90
+;
+; Add KiSetProfileInterval, KiStartProfileInterrupt,
+; KiStopProfileInterrupt procedures.
+; KiProfileInterrupt ISR.
+; KiProfileList, KiProfileLock are delcared here.
+;
+; shielint 10-Dec-90
+; Add performance counter support.
+; Move system clock to irq8, ie we now use RTC to generate system
+; clock. Performance count and Profile use timer 1 counter 0.
+; The interval of the irq0 interrupt can be changed by
+; KiSetProfileInterval. Performance counter does not care about the
+; interval of the interrupt as long as it knows the rollover count.
+; Note: Currently I implemented 1 performance counter for the whole
+; i386 NT.
+;
+; John Vert (jvert) 11-Jul-1991
+; Moved from ke\i386 to hal\i386. Removed non-HAL stuff
+;
+; shie-lin tzong (shielint) 13-March-92
+; Move System clock back to irq0 and use RTC (irq8) to generate
+; profile interrupt. Performance counter and system clock use time1
+; counter 0 of 8254.
+;
+; Landy Wang (landy@corollary.com) 26-Mar-1992
+; Move much code into separate modules for easy inclusion by various
+; HAL builds.
+;
+; Add HalBeginSystemInterrupt() call at beginning of ProfileInterrupt
+; code - this must be done before any sti.
+; Also add HalpProfileInterrupt2ndEntry for additional processors to
+; join the flow of things.
+;
+;--
+
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+include i386\kimacro.inc
+include mac386.inc
+include i386\ix8259.inc
+include i386\ixcmos.inc
+ .list
+
+ EXTRNP _DbgBreakPoint,0,IMPORT
+ EXTRNP _KeProfileInterrupt,1,IMPORT
+ EXTRNP Kei386EoiHelper,0,IMPORT
+ EXTRNP _HalEndSystemInterrupt,2
+ EXTRNP _HalBeginSystemInterrupt,3
+ EXTRNP _HalpAcquireCmosSpinLock ,0
+ EXTRNP _HalpReleaseCmosSpinLock ,0
+
+;
+; Constants used to initialize CMOS/Real Time Clock
+;
+
+D_INT032 EQU 8E00h ; access word for 386 ring 0 interrupt gate
+REGISTER_B_ENABLE_PERIODIC_INTERRUPT EQU 01000010B
+ ; RT/CMOS Register 'B' Init byte
+ ; Values for byte shown are
+ ; Bit 7 = Update inhibit
+ ; Bit 6 = Periodic interrupt enable
+ ; Bit 5 = Alarm interrupt disable
+ ; Bit 4 = Update interrupt disable
+ ; Bit 3 = Square wave disable
+ ; Bit 2 = BCD data format
+ ; Bit 1 = 24 hour time mode
+ ; Bit 0 = Daylight Savings disable
+
+REGISTER_B_DISABLE_PERIODIC_INTERRUPT EQU 00000010B
+
+_DATA SEGMENT DWORD PUBLIC 'DATA'
+
+RegisterAProfileValue db 00101000B ; default interval = 3.90625 ms
+
+align 4
+ProfileIntervalTable dd 1221 ; unit = 100 ns
+ dd 2441
+ dd 4883
+ dd 9766
+ dd 19531
+ dd 39063
+ dd 78125
+ dd 156250
+ dd 312500
+ dd 625000
+ dd 1250000
+ dd 2500000
+ dd 5000000
+ dd 5000000 OR 80000000H
+
+ProfileIntervalInitTable db 00100011B
+ db 00100100B
+ db 00100101B
+ db 00100110B
+ db 00100111B
+ db 00101000B
+ db 00101001B
+ db 00101010B
+ db 00101011B
+ db 00101100B
+ db 00101101B
+ db 00101110B
+ db 00101111B
+ db 00101111B
+
+;
+; The following array stores the per microsecond loop count for each
+; central processor.
+;
+
+HalpProfileInterval dd -1
+HalpProfilingStopped dd 1
+
+;
+; HALs wishing to reuse the code in this module should set the HAL
+; global variable IxProfileVector to their profile vector.
+;
+ public _IxProfileVector
+_IxProfileVector dd PROFILE_VECTOR
+
+_DATA ends
+
+
+_TEXT SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+;++
+;
+; HalStartProfileInterrupt(
+; IN ULONG Reserved
+; );
+;
+; Routine Description:
+;
+; What we do here is change the interrupt
+; rate from the slowest thing we can get away with to the value
+; that's been KeSetProfileInterval
+;
+; All processors will run this routine, but it doesn't hurt to have
+; each one reinitialize the CMOS, since none of them will be let go
+; from the stall until they all finish.
+;
+;--
+
+cPublicProc _HalStartProfileInterrupt ,1
+
+; Mark profiling as active
+;
+
+ mov dword ptr HalpProfilingStopped, 0
+
+;
+; Set the interrupt rate to what is actually needed
+;
+ stdCall _HalpAcquireCmosSpinLock ; intr disabled
+
+ mov al, RegisterAProfileValue
+ shl ax, 8
+ mov al, 0AH ; Register A
+ CMOS_WRITE ; Initialize it
+;
+; Don't clobber the Daylight Savings Time bit in register B, because we
+; stash the LastKnownGood "environment variable" there.
+;
+ mov ax, 0bh
+ CMOS_READ
+ and al, 1
+ mov ah, al
+ or ah, REGISTER_B_ENABLE_PERIODIC_INTERRUPT
+ mov al, 0bh
+ CMOS_WRITE ; Initialize it
+ mov al,0CH ; Register C
+ CMOS_READ ; Read to initialize
+ mov al,0DH ; Register D
+ CMOS_READ ; Read to initialize
+
+ stdCall _HalpReleaseCmosSpinLock
+
+ stdRET _HalStartProfileInterrupt
+
+stdENDP _HalStartProfileInterrupt
+
+
+
+;++
+;
+; HalStopProfileInterrupt(
+; IN ULONG Reserved
+; );
+;
+; Routine Description:
+;
+; What we do here is change the interrupt
+; rate from the high profiling rate to the slowest thing we
+; can get away with for PerformanceCounter rollover notification.
+;
+;--
+
+cPublicProc _HalStopProfileInterrupt ,1
+
+;
+; Turn off profiling hit computation and profile interrupt
+;
+
+;
+; Don't clobber the Daylight Savings Time bit in register B, because we
+; stash the LastKnownGood "environment variable" there.
+
+ stdCall _HalpAcquireCmosSpinLock ; intr disabled
+ mov ax, 0bh
+ CMOS_READ
+ and al, 1
+ mov ah, al
+ or ah, REGISTER_B_DISABLE_PERIODIC_INTERRUPT
+ mov al, 0bh
+ CMOS_WRITE ; Initialize it
+ mov al,0CH ; Register C
+ CMOS_READ ; dismiss pending profiling interrupt
+ mov dword ptr HalpProfilingStopped, 1
+ stdCall _HalpReleaseCmosSpinLock
+
+ stdRET _HalStopProfileInterrupt
+
+stdENDP _HalStopProfileInterrupt
+
+;++
+; ULONG
+; HalSetProfileInterval (
+; ULONG Interval
+; );
+;
+; Routine Description:
+;
+; This procedure sets the interrupt rate (and thus the sampling
+; interval) for the profiling interrupt.
+;
+; If profiling is active (KiProfilingStopped == 0) the actual
+; hardware interrupt rate will be set. Otherwise, a simple
+; rate validation computation is done.
+;
+; Arguments:
+;
+; (TOS+4) - Interval in 100ns unit.
+;
+; Return Value:
+;
+; Interval actually used by system.
+;
+;--
+
+cPublicProc _HalSetProfileInterval ,1
+
+ mov edx, [esp+4] ; [edx] = interval in 100ns unit
+ and edx, 7FFFFFFFh ; Remove highest bit.
+ mov ecx, 0 ; index = 0
+
+Hspi00:
+ mov eax, ProfileIntervalTable[ecx * 4]
+ cmp edx, eax ; if request interval < suport interval
+ jbe short Hspi10 ; if be, find supported interval
+ inc ecx
+ jmp short Hspi00
+
+Hspi10:
+ and eax, 7FFFFFFFh ; remove highest bit from supported interval
+ jecxz short Hspi20 ; If first entry then use it
+
+ push esi ; See which is closer to requested
+ mov esi, eax ; rate - current entry, or preceeding
+ sub esi, edx
+
+ sub edx, ProfileIntervalTable[ecx * 4 - 4]
+ cmp esi, edx
+ pop esi
+ jc short Hspi20
+
+ dec ecx ; use preceeding entry
+ mov eax, ProfileIntervalTable[ecx * 4]
+
+Hspi20:
+ push eax ; save interval value
+ mov al, ProfileIntervalInitTable[ecx]
+ mov RegisterAProfileValue, al
+ test dword ptr HalpProfilingStopped,-1
+ jnz short Hspi90
+
+ stdCall _HalStartProfileInterrupt,<0> ; Re-start profile interrupt
+ ; with the new interval
+
+Hspi90: pop eax
+ stdRET _HalSetProfileInterval ; (eax) = cReturn interval
+
+stdENDP _HalSetProfileInterval
+
+ page ,132
+ subttl "System Profile Interrupt"
+;++
+;
+; Routine Description:
+;
+; This routine is entered as the result of a profile interrupt.
+; Its function is to dismiss the interrupt, raise system Irql to
+; PROFILE_LEVEL and transfer control to
+; the standard system routine to process any active profiles.
+;
+; Arguments:
+;
+; None
+; Interrupt is disabled
+;
+; Return Value:
+;
+; Does not return, jumps directly to KeProfileInterrupt, which returns
+;
+; Sets Irql = PROFILE_LEVEL and dismisses the interrupt
+;
+;--
+ ENTER_DR_ASSIST Hpi_a, Hpi_t
+
+cPublicProc _HalpProfileInterrupt ,0
+
+;
+; Save machine state in trap frame
+;
+
+ ENTER_INTERRUPT Hpi_a, Hpi_t
+
+;
+; (esp) - base of trap frame
+;
+; HalBeginSystemInterrupt must be called before any sti's
+;
+;
+
+ push _IxProfileVector
+ sub esp, 4 ; allocate space to save OldIrql
+ stdCall _HalBeginSystemInterrupt, <PROFILE_LEVEL,_IxProfileVector,esp>
+
+ or al,al ; check for spurious interrupt
+ jz short Hpi100
+
+
+;
+; This is the RTC interrupt, so we have to clear the
+; interrupt flag on the RTC.
+;
+ stdCall _HalpAcquireCmosSpinLock
+
+;
+; clear interrupt flag on RTC by banging on the CMOS. On some systems this
+; doesn't work the first time we do it, so we do it twice. It is rumored that
+; some machines require more than this, but that hasn't been observed with NT.
+;
+
+ mov al,0CH ; Register C
+ CMOS_READ ; Read to initialize
+ mov al,0CH ; Register C
+ CMOS_READ ; Read to initialize
+if DBG
+ align 4
+Hpi10: test al, 80h
+ jz short Hpi15
+ mov al,0CH ; Register C
+ CMOS_READ ; Read to initialize
+ jmp short Hpi10
+Hpi15:
+endif ; DBG
+
+ stdCall _HalpReleaseCmosSpinLock
+
+ sti
+;
+; This entry point is provided for symmetric multiprocessor HALs.
+; Since it only makes sense for one processor to clear the CMOS,
+; all other processors can instead jmp into this entry point.
+;
+
+ align 4
+ public _HalpProfileInterrupt2ndEntry@0
+_HalpProfileInterrupt2ndEntry@0:
+
+;
+; (esp) = OldIrql
+; (esp+4) = H/W vector
+; (esp+8) = base of trap frame
+;
+
+;
+; Now check for any profiling stuff to do.
+;
+
+ cmp HalpProfilingStopped, dword ptr 1 ; Has profiling been stopped?
+ jz short Hpi90 ; if z, prof disenabled
+
+ stdCall _KeProfileInterrupt,<ebp> ; (ebp) = trapframe
+
+Hpi90:
+ INTERRUPT_EXIT
+
+ align 4
+Hpi100:
+ add esp, 8 ; spurious, no EndOfInterrupt
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+stdENDP _HalpProfileInterrupt
+
+_TEXT ends
+
+ end
diff --git a/private/ntos/nthals/halx86/i386/ixreboot.c b/private/ntos/nthals/halx86/i386/ixreboot.c
new file mode 100644
index 000000000..a310dd73d
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixreboot.c
@@ -0,0 +1,143 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ixreboot.c
+
+Abstract:
+
+ Provides the interface to the firmware for x86. Since there is no
+ firmware to speak of on x86, this is just reboot support.
+
+Author:
+
+ John Vert (jvert) 12-Aug-1991
+
+Revision History:
+
+--*/
+#include "halp.h"
+
+//
+// Defines to let us diddle the CMOS clock and the keyboard
+//
+
+#define CMOS_CTRL (PUCHAR )0x70
+#define CMOS_DATA (PUCHAR )0x71
+
+#define RESET 0xfe
+#define KEYBPORT (PUCHAR )0x64
+
+//
+// Private function prototypes
+//
+
+VOID
+HalpReboot (
+ VOID
+ );
+
+VOID
+HalpReboot (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure resets the CMOS clock to the standard timer settings
+ so the bios will work, and then issues a reset command to the keyboard
+ to cause a warm boot.
+
+ It is very machine dependent, this implementation is intended for
+ PC-AT like machines.
+
+ This code copied from the "old debugger" sources.
+
+ N.B.
+
+ Will NOT return.
+
+--*/
+
+{
+ UCHAR Scratch;
+ PUSHORT Magic;
+
+ //
+ // By sticking 0x1234 at physical location 0x472, we can bypass the
+ // memory check after a reboot.
+ //
+
+ Magic = HalpMapPhysicalMemory(0, 1);
+ Magic[0x472 / sizeof(USHORT)] = 0x1234;
+
+ //
+ // Turn off interrupts
+ //
+
+ HalpAcquireCmosSpinLock();
+
+ _asm {
+ cli
+ }
+
+ //
+ // Reset the cmos clock to a standard value
+ // (We are setting the periodic interrupt control on the MC147818)
+ //
+
+ //
+ // Disable periodic interrupt
+ //
+
+ WRITE_PORT_UCHAR(CMOS_CTRL, 0x0b); // Set up for control reg B.
+ KeStallExecutionProcessor(1);
+
+ Scratch = READ_PORT_UCHAR(CMOS_DATA);
+ KeStallExecutionProcessor(1);
+
+ Scratch &= 0xbf; // Clear periodic interrupt enable
+
+ WRITE_PORT_UCHAR(CMOS_DATA, Scratch);
+ KeStallExecutionProcessor(1);
+
+ //
+ // Set "standard" divider rate
+ //
+
+ WRITE_PORT_UCHAR(CMOS_CTRL, 0x0a); // Set up for control reg A.
+ KeStallExecutionProcessor(1);
+
+ Scratch = READ_PORT_UCHAR(CMOS_DATA);
+ KeStallExecutionProcessor(1);
+
+ Scratch &= 0xf0; // Clear rate setting
+ Scratch |= 6; // Set default rate and divider
+
+ WRITE_PORT_UCHAR(CMOS_DATA, Scratch);
+ KeStallExecutionProcessor(1);
+
+ //
+ // Set a "neutral" cmos address to prevent weirdness
+ // (Why is this needed? Source this was copied from doesn't say)
+ //
+
+ WRITE_PORT_UCHAR(CMOS_CTRL, 0x15);
+ KeStallExecutionProcessor(1);
+
+ HalpResetAllProcessors();
+
+ //
+ // If we return, send the reset command to the keyboard controller
+ //
+
+ WRITE_PORT_UCHAR(KEYBPORT, RESET);
+
+ _asm {
+ hlt
+ }
+}
diff --git a/private/ntos/nthals/halx86/i386/ixstall.asm b/private/ntos/nthals/halx86/i386/ixstall.asm
new file mode 100644
index 000000000..3bc27318c
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixstall.asm
@@ -0,0 +1,480 @@
+
+ title "Stall Execution Support"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; ixstall.asm
+;
+; Abstract:
+;
+; This module implements the code necessary to field and process the
+; interval clock interrupt.
+;
+; Author:
+;
+; Shie-Lin Tzong (shielint) 12-Jan-1990
+;
+; Environment:
+;
+; Kernel mode only.
+;
+; Revision History:
+;
+; bryanwi 20-Sep-90
+;
+; Add KiSetProfileInterval, KiStartProfileInterrupt,
+; KiStopProfileInterrupt procedures.
+; KiProfileInterrupt ISR.
+; KiProfileList, KiProfileLock are delcared here.
+;
+; shielint 10-Dec-90
+; Add performance counter support.
+; Move system clock to irq8, ie we now use RTC to generate system
+; clock. Performance count and Profile use timer 1 counter 0.
+; The interval of the irq0 interrupt can be changed by
+; KiSetProfileInterval. Performance counter does not care about the
+; interval of the interrupt as long as it knows the rollover count.
+; Note: Currently I implemented 1 performance counter for the whole
+; i386 NT.
+;
+; John Vert (jvert) 11-Jul-1991
+; Moved from ke\i386 to hal\i386. Removed non-HAL stuff
+;
+; shie-lin tzong (shielint) 13-March-92
+; Move System clock back to irq0 and use RTC (irq8) to generate
+; profile interrupt. Performance counter and system clock use time1
+; counter 0 of 8254.
+;
+; Landy Wang (corollary!landy) 04-Dec-92
+; Created this module by moving routines from ixclock.asm to here.
+;
+;--
+
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+include i386\ix8259.inc
+include i386\kimacro.inc
+include mac386.inc
+include i386\ixcmos.inc
+ .list
+
+ EXTRNP _DbgBreakPoint,0,IMPORT
+ EXTRNP _HalpAcquireCmosSpinLock ,0
+ EXTRNP _HalpReleaseCmosSpinLock ,0
+
+;
+; Constants used to initialize CMOS/Real Time Clock
+;
+
+D_INT032 EQU 8E00h ; access word for 386 ring 0 interrupt gate
+RTCIRQ EQU 8 ; IRQ number for RTC interrupt
+REGISTER_B_ENABLE_PERIODIC_INTERRUPT EQU 01000010B
+ ; RT/CMOS Register 'B' Init byte
+ ; Values for byte shown are
+ ; Bit 7 = Update inhibit
+ ; Bit 6 = Periodic interrupt enable
+ ; Bit 5 = Alarm interrupt disable
+ ; Bit 4 = Update interrupt disable
+ ; Bit 3 = Square wave disable
+ ; Bit 2 = BCD data format
+ ; Bit 1 = 24 hour time mode
+ ; Bit 0 = Daylight Savings disable
+
+REGISTER_B_DISABLE_PERIODIC_INTERRUPT EQU 00000010B
+
+;
+; RegisterAInitByte sets 8Hz clock rate, used during init to set up
+; KeStallExecutionProcessor, etc. (See RegASystemClockByte below.)
+;
+
+RegisterAInitByte EQU 00101101B ; RT/CMOS Register 'A' init byte
+ ; 32.768KHz Base divider rate
+ ; 8Hz int rate, period = 125.0ms
+PeriodInMicroSecond EQU 125000 ;
+
+_DATA SEGMENT DWORD PUBLIC 'DATA'
+
+HalpP0BugBugStallCount dd 0
+
+_DATA ends
+
+INIT SEGMENT PARA PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+ page ,132
+ subttl "Initialize Stall Execution Counter"
+;++
+;
+; VOID
+; HalpInitializeStallExecution (
+; IN CCHAR ProcessorNumber
+; )
+;
+; Routine Description:
+;
+; This routine initialize the per Microsecond counter for
+; KeStallExecutionProcessor
+;
+; Arguments:
+;
+; ProcessorNumber - Processor Number
+;
+; Return Value:
+;
+; None.
+;
+; Note:
+;
+; Current implementation assumes that all the processors share
+; the same Real Time Clock. So, the dispatcher database lock is
+; acquired before entering this routine to guarantee only one
+; processor can access the routine.
+;
+;--
+
+KiseInterruptCount equ [ebp-12] ; local variable
+
+cPublicProc _HalpInitializeStallExecution ,1
+
+ifndef NT_UP
+;;
+;; This function currently doesn't work from any processor but the
+;; boot processor - for now stub out the others
+;;
+
+ mov eax, PCR[PcPrcb]
+ cmp byte ptr [eax].PbNumber, 0
+ je @f
+
+ mov eax, HalpP0BugBugStallCount
+ mov PCR[PcStallScaleFactor], eax
+ stdRET _HalpInitializeStallExecution
+@@:
+endif
+
+ push ebp ; save ebp
+ mov ebp, esp ; set up 12 bytes for local use
+ sub esp, 12
+
+ pushfd ; save caller's eflag
+
+;
+; Initialize Real Time Clock to interrupt us for every 125ms at
+; IRQ 8.
+;
+
+ cli ; make sure interrupts are disabled
+
+;
+; Get and save current 8259 masks
+;
+
+ xor eax,eax
+
+;
+; Assume there is no third and fourth PICs
+;
+; Get interrupt Mask on PIC2
+;
+
+ in al,PIC2_PORT1
+ shl eax, 8
+
+;
+; Get interrupt Mask on PIC1
+;
+
+ in al,PIC1_PORT1
+ push eax ; save the masks
+ mov eax, NOT (( 1 SHL PIC_SLAVE_IRQ) + (1 SHL RTCIRQ))
+ ; Mask all the irqs except irq 2 and 8
+ SET_8259_MASK ; Set 8259's int mask register
+
+;
+; Since RTC interrupt will come from IRQ 8, we need to
+; Save original irq 8 descriptor and set the descriptor to point to
+; our own handler.
+;
+
+ sidt fword ptr [ebp-8] ; get IDT address
+ mov ecx, [ebp-6] ; (ecx)->IDT
+
+ mov eax, (RTCIRQ+PRIMARY_VECTOR_BASE)
+
+ shl eax, 3 ; 8 bytes per IDT entry
+ add ecx, eax ; now at the correct IDT RTC entry
+
+ push dword ptr [ecx] ; (TOS) = original desc of IRQ 8
+ push dword ptr [ecx + 4] ; each descriptor has 8 bytes
+
+ ;
+ ; Pushing the appropriate entry address now (instead of
+ ; the IDT start address later) to make the pop at the end simpler.
+ ;
+ push ecx ; (TOS) -> &IDT[HalProfileVector]
+
+ mov eax, offset FLAT:RealTimeClockHandler
+
+ mov word ptr [ecx], ax ; Lower half of handler addr
+ mov word ptr [ecx+2], KGDT_R0_CODE ; set up selector
+ mov word ptr [ecx+4], D_INT032 ; 386 interrupt gate
+
+ shr eax, 16 ; (ax)=higher half of handler addr
+ mov word ptr [ecx+6], ax
+
+ mov dword ptr KiseinterruptCount, 0 ; set no interrupt yet
+
+ stdCall _HalpAcquireCmosSpinLock ; intr disabled
+
+ mov ax,(RegisterAInitByte SHL 8) OR 0AH ; Register A
+ CMOS_WRITE ; Initialize it
+;
+; Don't clobber the Daylight Savings Time bit in register B, because we
+; stash the LastKnownGood "environment variable" there.
+;
+ mov ax, 0bh
+ CMOS_READ
+ and al, 1
+ mov ah, al
+ or ah, REGISTER_B_ENABLE_PERIODIC_INTERRUPT
+ mov al, 0bh
+ CMOS_WRITE ; Initialize it
+ mov al,0CH ; Register C
+ CMOS_READ ; Read to initialize
+ mov al,0DH ; Register D
+ CMOS_READ ; Read to initialize
+ mov dword ptr [KiseInterruptCount], 0
+
+ stdCall _HalpReleaseCmosSpinLock
+
+;
+; Now enable the interrupt and start the counter
+; (As a matter of fact, only IRQ8 can come through.)
+;
+ xor eax, eax ; (eax) = 0, initialize loopcount
+ALIGN 16
+ sti
+ jmp kise10
+
+ALIGN 16
+kise10:
+ sub eax, 1 ; increment the loopcount
+ jnz short kise10
+
+if DBG
+;
+; Counter overflowed
+;
+
+ stdCall _DbgBreakPoint
+endif
+ jmp short kise10
+
+;
+; Our RealTimeClock interrupt handler. The control comes here through
+; irq 8.
+; Note: we discard first real time clock interrupt and compute the
+; permicrosecond loopcount on receiving of the second real time
+; interrupt. This is because the first interrupt is generated
+; based on the previous real time tick interval.
+;
+
+RealTimeClockHandler:
+
+ inc dword ptr KiseInterruptCount ; increment interrupt count
+ cmp dword ptr KiseInterruptCount,1 ; Is this the first interrupt?
+ jnz short kise25 ; no, its the second go process it
+ pop eax ; get rid of original ret addr
+ push offset FLAT:kise10 ; set new return addr
+
+
+ stdCall _HalpAcquireCmosSpinLock ; intr disabled
+
+ mov ax,(RegisterAInitByte SHL 8) OR 0AH ; Register A
+ CMOS_WRITE ; Initialize it
+;
+; Don't clobber the Daylight Savings Time bit in register B, because we
+; stash the LastKnownGood "environment variable" there.
+;
+ mov ax, 0bh
+ CMOS_READ
+ and al, 1
+ mov ah, al
+ or ah, REGISTER_B_ENABLE_PERIODIC_INTERRUPT
+ mov al, 0bh
+ CMOS_WRITE ; Initialize it
+ mov al,0CH ; Register C
+ CMOS_READ ; Read to initialize
+ mov al,0DH ; Register D
+ CMOS_READ ; Read to initialize
+
+ stdCall _HalpReleaseCmosSpinLock
+;
+; Dismiss the interrupt.
+;
+ mov al, OCW2_NON_SPECIFIC_EOI ; send non specific eoi to slave
+ out PIC2_PORT0, al
+ mov al, PIC2_EOI ; specific eoi to master for pic2 eoi
+ out PIC1_PORT0, al ; send irq2 specific eoi to master
+
+ xor eax, eax ; reset loop counter
+
+ iretd
+
+kise25:
+
+;
+; ** temporary - check for incorrect KeStallExecutionProcessorLoopCount
+;
+
+if DBG
+ cmp eax, 0
+ jnz short kise30
+ stdCall _DbgBreakPoint
+
+endif
+ ; never return
+;
+; ** End temporay code
+;
+
+kise30:
+ neg eax
+ xor edx, edx ; (edx:eax) = divident
+ mov ecx, PeriodInMicroSecond; (ecx) = time spent in the loop
+ div ecx ; (eax) = loop count per microsecond
+ cmp edx, 0 ; Is remainder =0?
+ jz short kise40 ; yes, go kise40
+ inc eax ; increment loopcount by 1
+kise40:
+ mov PCR[PcStallScaleFactor], eax
+ mov HalpP0BugBugStallCount, eax
+
+;
+; Reset return address to kexit
+;
+
+ pop eax ; discard original return address
+ push offset FLAT:kexit ; return to kexit
+ mov eax, (HIGHEST_LEVEL_FOR_8259 - RTCIRQ)
+
+;
+; Shutdown periodic interrupt
+;
+ stdCall _HalpAcquireCmosSpinLock
+ mov ax,(RegisterAInitByte SHL 8) OR 0AH ; Register A
+ CMOS_WRITE ; Initialize it
+ mov ax, 0bh
+ CMOS_READ
+ and al, 1
+ mov ah, al
+ or ah, REGISTER_B_DISABLE_PERIODIC_INTERRUPT
+ mov al, 0bh
+ CMOS_WRITE ; Initialize it
+ mov al,0CH ; Register C
+ CMOS_READ ; dismiss pending interrupt
+ stdCall _HalpReleaseCmosSpinLock
+
+;
+; Dismiss the interrupt.
+;
+ mov eax, RTCIRQ
+ mov al, OCW2_NON_SPECIFIC_EOI ; send non specific eoi to slave
+ out PIC2_PORT0, al
+ mov al, PIC2_EOI ; specific eoi to master for pic2 eoi
+ out PIC1_PORT0, al ; send irq2 specific eoi to master
+
+ and word ptr [esp+8], NOT 0200H ; Disable interrupt upon return
+ iretd
+
+kexit: ; Interrupts are disabled
+ pop ecx ; (ecx) -> &IDT[HalProfileVector]
+ pop [ecx+4] ; restore higher half of RTC desc
+ pop [ecx] ; restore lower half of RTC desc
+
+ pop eax ; (eax) = origianl 8259 int masks
+ SET_8259_MASK
+
+ popfd ; restore caller's eflags
+ mov esp, ebp
+ pop ebp ; restore ebp
+ stdRET _HalpInitializeStallExecution
+
+stdENDP _HalpInitializeStallExecution
+
+INIT ends
+
+_TEXT SEGMENT PARA PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+ page ,132
+ subttl "Stall Execution"
+;++
+;
+; VOID
+; KeStallExecutionProcessor (
+; IN ULONG MicroSeconds
+; )
+;
+; Routine Description:
+;
+; This function stalls execution for the specified number of microseconds.
+; KeStallExecutionProcessor
+;
+; Arguments:
+;
+; MicroSeconds - Supplies the number of microseconds that execution is to be
+; stalled.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+MicroSeconds equ [esp + 4]
+
+
+cPublicProc _KeStallExecutionProcessor ,1
+cPublicFpo 1, 0
+
+ mov ecx, MicroSeconds ; (ecx) = Microseconds
+ jecxz short kese10 ; return if no loop needed
+
+ mov eax, PCR[PcStallScaleFactor] ; get per microsecond
+ ; loop count for the processor
+ mul ecx ; (eax) = desired loop count
+
+if DBG
+;
+; Make sure we the loopcount is less than 4G and is not equal to zero
+;
+
+ cmp edx, 0
+ jz short @f
+ int 3
+
+@@: cmp eax,0
+ jnz short @f
+ int 3
+@@:
+endif
+ALIGN 16
+ jmp kese05
+
+ALIGN 16
+kese05: sub eax, 1 ; (eax) = (eax) - 1
+ jnz short kese05
+kese10:
+ stdRET _KeStallExecutionProcessor
+
+stdENDP _KeStallExecutionProcessor
+
+_TEXT ends
+
+ end
diff --git a/private/ntos/nthals/halx86/i386/ixswint.asm b/private/ntos/nthals/halx86/i386/ixswint.asm
new file mode 100644
index 000000000..2ca5c88e2
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixswint.asm
@@ -0,0 +1,327 @@
+ title "Software Interrupts"
+
+;++
+;
+; Copyright (c) 1992 Microsoft Corporation
+;
+; Module Name:
+;
+; ixswint.asm
+;
+; Abstract:
+;
+; This module implements the software interrupt handlers
+; for x86 machines
+;
+; Author:
+;
+; John Vert (jvert) 2-Jan-1992
+;
+; Environment:
+;
+; Kernel mode only.
+;
+; Revision History:
+;
+;--
+
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+include i386\ix8259.inc
+include i386\kimacro.inc
+ .list
+
+ EXTRNP _KiDeliverApc,3,IMPORT
+ EXTRNP _KiDispatchInterrupt,0,IMPORT
+ EXTRNP Kei386EoiHelper,0,IMPORT
+ EXTRNP _HalEndSystemInterrupt,2
+ extrn SWInterruptHandlerTable:dword
+ extrn SWInterruptLookUpTable:byte
+ifdef IRQL_METRICS
+ extrn HalApcSoftwareIntCount:dword
+ extrn HalDpcSoftwareIntCount:dword
+endif
+
+_TEXT$02 SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING
+
+ page ,132
+ subttl "Request Software Interrupt"
+
+;++
+;
+; VOID
+; HalRequestSoftwareInterrupt (
+; IN KIRQL RequestIrql
+; )
+;
+; Routine Description:
+;
+; This routine is used to request a software interrupt to the
+; system. Also, this routine checks to see if any software
+; interrupt should be generated.
+; The following condition will cause software interrupt to
+; be simulated:
+; any software interrupt which has higher priority than
+; current IRQL's is pending.
+;
+; NOTE: This routine simulates software interrupt as long as
+; any pending SW interrupt level is higher than the current
+; IRQL, even when interrupts are disabled.
+;
+; Arguments:
+;
+; (cl) = RequestIrql - Supplies the request IRQL value
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+cPublicFastCall HalRequestSoftwareInterrupt ,1
+cPublicFpo 0, 1
+
+ mov eax,1
+ shl eax, cl ; convert to mask
+ pushfd ; save interrupt mode
+ cli ; disable interrupt
+ or PCR[PcIRR], eax ; set the request bit
+ mov cl, PCR[PcIrql] ; get current IRQL
+
+ mov eax, PCR[PcIRR] ; get SW interrupt request register
+ and eax, 3 ; mask off pending HW interrupts
+
+ xor edx, edx
+ mov dl, SWInterruptLookUpTable[eax] ; get the highest pending
+ ; software interrupt level
+ cmp dl, cl ; Is highest SW int level > irql?
+ jbe short KsiExit ; No, jmp ksiexit
+ call SWInterruptHandlerTable[edx*4] ; yes, simulate interrupt
+ ; to the appropriate handler
+KsiExit:
+ popfd ; restore original interrupt mode
+ fstRET HalRequestSoftwareInterrupt
+
+fstENDP HalRequestSoftwareInterrupt
+
+ page ,132
+ subttl "Request Software Interrupt"
+
+;++
+;
+; VOID
+; HalClearSoftwareInterrupt (
+; IN KIRQL RequestIrql
+; )
+;
+; Routine Description:
+;
+; This routine is used to clear a possible pending software interrupt.
+; Support for this function is optional, and allows the kernel to
+; reduce the number of spurious software interrupts it receives/
+;
+; Arguments:
+;
+; (cl) = RequestIrql - Supplies the request IRQL value
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+cPublicFastCall HalClearSoftwareInterrupt ,1
+cPublicFpo 0, 0
+
+ mov eax,1
+ shl eax, cl ; convert to mask
+
+ not eax
+ and PCR[PcIRR], eax ; clear pending irr bit
+
+ fstRET HalClearSoftwareInterrupt
+
+fstENDP HalClearSoftwareInterrupt
+
+
+
+ page ,132
+ subttl "Dispatch Interrupt"
+;++
+;
+; VOID
+; HalpDispatchInterrupt(
+; VOID
+; );
+;
+; Routine Description:
+;
+; This routine is the interrupt handler for a software interrupt generated
+; at DISPATCH_LEVEL. Its function is to save the machine state, raise
+; Irql to DISPATCH_LEVEL, dismiss the interrupt, and call the DPC
+; delivery routine.
+;
+; Arguments:
+;
+; None
+; Interrupt is disabled
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+ ENTER_DR_ASSIST hdpi_a, hdpi_t
+
+ align dword
+ public _HalpDispatchInterrupt
+_HalpDispatchInterrupt proc
+ifdef IRQL_METRICS
+ lock inc HalDpcSoftwareIntCount
+endif
+;
+; Create IRET frame on stack
+;
+ pop eax
+ pushfd
+ push cs
+ push eax
+
+;
+; Save machine state on trap frame
+;
+
+ ENTER_INTERRUPT hdpi_a, hdpi_t
+.FPO ( FPO_LOCALS+1, 0, 0, 0, 0, FPO_TRAPFRAME )
+
+ public _HalpDispatchInterrupt2ndEntry
+_HalpDispatchInterrupt2ndEntry:
+
+; Save previous IRQL and set new priority level
+
+ push PCR[PcIrql] ; save previous IRQL
+ mov byte ptr PCR[PcIrql], DISPATCH_LEVEL; set new irql
+ and dword ptr PCR[PcIRR], not (1 shl DISPATCH_LEVEL) ; clear the pending bit in IRR
+
+;
+; Now it is safe to enable interrupt to allow higher priority interrupt
+; to come in.
+;
+
+ sti
+
+;
+; Go do Dispatch Interrupt processing
+;
+ stdCall _KiDispatchInterrupt
+
+;
+; Do interrupt exit processing
+;
+
+ SOFT_INTERRUPT_EXIT ; will do an iret
+
+_HalpDispatchInterrupt endp
+
+ page ,132
+ subttl "APC Interrupt"
+;++
+;
+; HalpApcInterrupt(
+; VOID
+; );
+;
+; Routine Description:
+;
+; This routine is entered as the result of a software interrupt generated
+; at APC_LEVEL. Its function is to save the machine state, raise Irql to
+; APC_LEVEL, dismiss the interrupt, and call the APC delivery routine.
+;
+; Arguments:
+;
+; None
+; Interrupt is Disabled
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+ ENTER_DR_ASSIST hapc_a, hapc_t
+
+ align dword
+ public _HalpApcInterrupt
+_HalpApcInterrupt proc
+ifdef IRQL_METRICS
+ lock inc HalApcSoftwareIntCount
+endif
+;
+; Create IRET frame on stack
+;
+ pop eax
+ pushfd
+ push cs
+ push eax
+
+;
+; Save machine state in trap frame
+;
+ ENTER_INTERRUPT hapc_a, hapc_t
+.FPO ( FPO_LOCALS+1, 0, 0, 0, 0, FPO_TRAPFRAME )
+
+
+ public _HalpApcInterrupt2ndEntry
+_HalpApcInterrupt2ndEntry:
+
+;
+; Save previous IRQL and set new priority level
+;
+
+ push PCR[PcIrql] ; save previous Irql
+ mov byte ptr PCR[PcIrql], APC_LEVEL ; set new Irql
+ and dword ptr PCR[PcIRR], not (1 shl APC_LEVEL) ; dismiss pending APC
+;
+; Now it is safe to enable interrupt to allow higher priority interrupt
+; to come in.
+;
+
+ sti
+
+;
+; call the APC delivery routine.
+;
+
+ mov eax, [ebp]+TsSegCs ; get interrupted code's CS
+ and eax, MODE_MASK ; extract the mode
+
+ test dword ptr [ebp]+TsEFlags, EFLAGS_V86_MASK
+ jz short @f
+
+ or eax, MODE_MASK ; If v86 frame, then set user_mode
+@@:
+
+;
+; call APC deliver routine
+; Previous mode
+; Null exception frame
+; Trap frame
+
+ stdCall _KiDeliverApc, <eax, 0,ebp>
+
+;
+;
+; Do interrupt exit processing
+;
+
+ SOFT_INTERRUPT_EXIT ; will do an iret
+
+_HalpApcInterrupt endp
+
+_TEXT$02 ends
+
+ end
diff --git a/private/ntos/nthals/halx86/i386/ixsysbus.c b/private/ntos/nthals/halx86/i386/ixsysbus.c
new file mode 100644
index 000000000..a5463cb31
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixsysbus.c
@@ -0,0 +1,188 @@
+/*++
+
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ ixsysbus.c
+
+Abstract:
+
+Author:
+
+Environment:
+
+Revision History:
+
+
+--*/
+
+#include "halp.h"
+
+ULONG HalpDefaultInterruptAffinity;
+
+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.
+
+--*/
+{
+ ULONG SystemVector;
+
+ UNREFERENCED_PARAMETER( BusHandler );
+ UNREFERENCED_PARAMETER( RootHandler );
+ UNREFERENCED_PARAMETER( BusInterruptVector );
+
+ SystemVector = BusInterruptLevel + PRIMARY_VECTOR_BASE;
+ if (SystemVector < PRIMARY_VECTOR_BASE ||
+ SystemVector > PRIMARY_VECTOR_BASE + HIGHEST_LEVEL_FOR_8259 ||
+ HalpIDTUsage[SystemVector].Flags & IDTOwned ) {
+
+ //
+ // This is an illegal BusInterruptVector and cannot be connected.
+ //
+
+ return(0);
+ }
+
+ *Irql = (KIRQL)(HIGHEST_LEVEL_FOR_8259 + PRIMARY_VECTOR_BASE - SystemVector);
+ *Affinity = HalpDefaultInterruptAffinity;
+ ASSERT(HalpDefaultInterruptAffinity);
+ return SystemVector;
+}
+
diff --git a/private/ntos/nthals/halx86/i386/ixsysint.asm b/private/ntos/nthals/halx86/i386/ixsysint.asm
new file mode 100644
index 000000000..e73b40f24
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixsysint.asm
@@ -0,0 +1,582 @@
+;++
+;
+;Copyright (c) 1991 Microsoft Corporation
+;
+;Module Name:
+;
+; ixsysint.asm
+;
+;Abstract:
+;
+; This module implements the HAL routines to enable/disable system
+; interrupts.
+;
+;Author:
+;
+; John Vert (jvert) 22-Jul-1991
+;
+;Environment:
+;
+; Kernel Mode
+;
+;Revision History:
+;
+;--
+
+
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+include i386\ix8259.inc
+include i386\kimacro.inc
+include mac386.inc
+ .list
+
+ extrn KiI8259MaskTable:DWORD
+ EXTRNP _KeBugCheck,1,IMPORT
+
+ifdef IRQL_METRICS
+ extrn HalPostponedIntCount:dword
+endif
+ extrn _PciIsaIrq:dword
+ extrn SWInterruptHandlerTable:dword
+ extrn HalpHardwareInterruptLevel:proc
+
+;
+; Constants used to initialize CMOS/Real Time Clock
+;
+
+CMOS_CONTROL_PORT EQU 70h ; command port for cmos
+CMOS_DATA_PORT EQU 71h ; cmos data port
+
+;
+; Macros to Read/Write/Reset CMOS to initialize RTC
+;
+
+; CMOS_READ
+;
+; Description: This macro read a byte from the CMOS register specified
+; in (AL).
+;
+; Parameter: (AL) = address/register to read
+; Return: (AL) = data
+;
+
+CMOS_READ MACRO
+ OUT CMOS_CONTROL_PORT,al ; ADDRESS LOCATION AND DISABLE NMI
+ IODelay ; I/O DELAY
+ IN AL,CMOS_DATA_PORT ; READ IN REQUESTED CMOS DATA
+ IODelay ; I/O DELAY
+ENDM
+
+_DATA SEGMENT DWORD PUBLIC 'DATA'
+
+align dword
+;
+; HalDismissSystemInterrupt does an indirect jump through this table so it
+; can quickly execute specific code for different interrupts.
+;
+ public HalpSpecialDismissTable
+HalpSpecialDismissTable label dword
+ dd offset FLAT:HalpDismissNormal ; irq 0
+ dd offset FLAT:HalpDismissNormal ; irq 1
+ dd offset FLAT:HalpDismissNormal ; irq 2
+ dd offset FLAT:HalpDismissNormal ; irq 3
+ dd offset FLAT:HalpDismissNormal ; irq 4
+ dd offset FLAT:HalpDismissNormal ; irq 5
+ dd offset FLAT:HalpDismissNormal ; irq 6
+ dd offset FLAT:HalpDismissIrq07 ; irq 7
+ dd offset FLAT:HalpDismissNormal ; irq 8
+ dd offset FLAT:HalpDismissNormal ; irq 9
+ dd offset FLAT:HalpDismissNormal ; irq A
+ dd offset FLAT:HalpDismissNormal ; irq B
+ dd offset FLAT:HalpDismissNormal ; irq C
+ dd offset FLAT:HalpDismissIrq0d ; irq D
+ dd offset FLAT:HalpDismissNormal ; irq E
+ dd offset FLAT:HalpDismissIrq0f ; irq F
+ dd offset FLAT:HalpDismissNormal ; irq 10
+ dd offset FLAT:HalpDismissNormal ; irq 11
+ dd offset FLAT:HalpDismissNormal ; irq 12
+ dd offset FLAT:HalpDismissNormal ; irq 13
+ dd offset FLAT:HalpDismissNormal ; irq 14
+ dd offset FLAT:HalpDismissNormal ; irq 15
+ dd offset FLAT:HalpDismissNormal ; irq 16
+ dd offset FLAT:HalpDismissNormal ; irq 17
+ dd offset FLAT:HalpDismissNormal ; irq 18
+ dd offset FLAT:HalpDismissNormal ; irq 19
+ dd offset FLAT:HalpDismissNormal ; irq 1A
+ dd offset FLAT:HalpDismissNormal ; irq 1B
+ dd offset FLAT:HalpDismissNormal ; irq 1C
+ dd offset FLAT:HalpDismissNormal ; irq 1D
+ dd offset FLAT:HalpDismissNormal ; irq 1E
+ dd offset FLAT:HalpDismissNormal ; irq 1F
+ dd offset FLAT:HalpDismissNormal ; irq 20
+ dd offset FLAT:HalpDismissNormal ; irq 21
+ dd offset FLAT:HalpDismissNormal ; irq 22
+ dd offset FLAT:HalpDismissNormal ; irq 23
+
+ public HalpSpecialDismissLevelTable
+HalpSpecialDismissLevelTable label dword
+ dd offset FLAT:HalpDismissLevel ; irq 0
+ dd offset FLAT:HalpDismissLevel ; irq 1
+ dd offset FLAT:HalpDismissLevel ; irq 2
+ dd offset FLAT:HalpDismissLevel ; irq 3
+ dd offset FLAT:HalpDismissLevel ; irq 4
+ dd offset FLAT:HalpDismissLevel ; irq 5
+ dd offset FLAT:HalpDismissLevel ; irq 6
+ dd offset FLAT:HalpDismissIrq07Level ; irq 7
+ dd offset FLAT:HalpDismissLevel ; irq 8
+ dd offset FLAT:HalpDismissLevel ; irq 9
+ dd offset FLAT:HalpDismissLevel ; irq A
+ dd offset FLAT:HalpDismissLevel ; irq B
+ dd offset FLAT:HalpDismissLevel ; irq C
+ dd offset FLAT:HalpDismissIrq0dLevel ; irq D
+ dd offset FLAT:HalpDismissLevel ; irq E
+ dd offset FLAT:HalpDismissIrq0fLevel ; irq F
+
+_DATA ENDS
+
+_TEXT$01 SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+
+;++
+;BOOLEAN
+;HalBeginSystemInterrupt(
+; IN KIRQL Irql
+; IN CCHAR Vector,
+; OUT PKIRQL OldIrql
+; )
+;
+;
+;
+;Routine Description:
+;
+; This routine is used to dismiss the specified vector number. It is called
+; before any interrupt service routine code is executed.
+;
+; N.B. This routine does NOT preserve EAX or EBX
+;
+; On a UP machine the interrupt dismissed at BeginSystemInterrupt time.
+; This is fine since the irql is being raise to mask it off.
+; HalEndSystemInterrupt is simply a LowerIrql request.
+;
+;
+;Arguments:
+;
+; Irql - Supplies the IRQL to raise to
+;
+; Vector - Supplies the vector of the interrupt to be dismissed
+;
+; OldIrql- Location to return OldIrql
+;
+;
+;Return Value:
+;
+; FALSE - Interrupt is spurious and should be ignored
+;
+; TRUE - Interrupt successfully dismissed and Irql raised.
+;
+;--
+align dword
+HbsiIrql equ byte ptr [esp+4]
+HbsiVector equ byte ptr [esp+8]
+HbsiOldIrql equ dword ptr [esp+12]
+
+cPublicProc _HalBeginSystemInterrupt ,3
+.FPO ( 0, 3, 0, 0, 0, 0 )
+ xor ecx, ecx
+ mov cl, HbsiVector ; (ecx) = System Vector
+ sub ecx, PRIMARY_VECTOR_BASE ; (ecx) = 8259 IRQ #
+if DBG
+ cmp ecx, 1fh
+ jbe hbsi00
+ int 3
+hbsi00:
+
+endif
+ jmp HalpSpecialDismissTable[ecx*4]
+
+HalpDismissIrq0f:
+;
+; Check to see if this is a spurious interrupt
+;
+ mov al, OCW3_READ_ISR ; tell 8259 we want to read ISR
+ out PIC2_PORT0, al
+ IODelay ; delay
+ in al, PIC2_PORT0 ; (al) = content of PIC 1 ISR
+ test al, 10000000B ; Is In-Service register set?
+ jnz short HalpDismissNormal ; No, this is NOT a spurious int,
+ ; go do the normal interrupt stuff
+HalpIrq0fSpurious:
+;
+; This is a spurious interrupt.
+; Because the slave PIC is cascaded to irq2 of master PIC, we need to
+; dismiss the interupt on master PIC's irq2.
+;
+
+ mov al, PIC2_EOI ; Specific eoi to master for pic2 eoi
+ out PIC1_PORT0, al ; send irq2 specific eoi to master
+ mov eax,0 ; return FALSE
+ stdRET _HalBeginSystemInterrupt
+
+HalpDismissIrq07:
+;
+; Check to see if this is a spurious interrupt
+;
+ mov al, OCW3_READ_ISR ; tell 8259 we want to read ISR
+ out PIC1_PORT0, al
+ IODelay ; delay
+ in al, PIC1_PORT0 ; (al) = content of PIC 1 ISR
+ test al, 10000000B ; Is In-Service register set?
+ jnz HalpDismissNormal ; No, so this is NOT a spurious int
+ mov eax, 0 ; return FALSE
+ stdRET _HalBeginSystemInterrupt
+
+HalpDismissIrq0d:
+;
+; Clear the NPX busy latch.
+;
+
+ xor al,al
+ out I386_80387_BUSY_PORT, al
+
+align 4
+HalpDismissNormal:
+;
+; Raise IRQL to requested level
+;
+ xor ebx,ebx
+ mov al, HbsiIrql ; (al) = New irql
+ ; (ecx) = IRQ #
+ mov bl, PCR[PcIrql] ; (ebx) = Current Irql
+
+;
+; Now we check to make sure the Irql of this interrupt > current Irql.
+; If it is not, we dismiss it as spurious and set the appropriate bit
+; in the IRR so we can dispatch the interrupt when Irql is lowered
+;
+ cmp al, bl
+ jbe Hdsi300
+
+ mov PCR[PcIrql], al ; set new Irql
+ mov edx, HbsiOldIrql ; save current irql to OldIrql variable
+ mov byte ptr [edx], bl
+
+;
+; Dismiss interrupt.
+;
+ mov eax, ecx ; (eax) = IRQ #
+ cmp eax, 8 ; EOI to master or slave?
+ jae short Hbsi100 ; EIO to both master and slave
+
+ or al, PIC1_EOI_MASK ; create specific eoi mask for master
+ out PIC1_PORT0, al ; dismiss the interrupt
+ sti
+ mov eax, 1 ; return TRUE
+ stdRET _HalBeginSystemInterrupt
+
+align 4
+Hbsi100:
+ add al, OCW2_SPECIFIC_EOI - 8 ; specific eoi to slave
+ out PIC2_PORT0, al
+
+ mov al, PIC2_EOI ; specific eoi to master for pic2 eoi
+ out PIC1_PORT0, al ; send irq2 specific eoi to master
+ sti
+ mov eax, 1 ; return TRUE
+ stdRET _HalBeginSystemInterrupt
+
+align 4
+Hdsi300:
+;
+; An interrupt has come in at a lower Irql, so we dismiss it as spurious and
+; set the appropriate bit in the IRR so that KeLowerIrql knows to dispatch
+; it when Irql is lowered.
+;
+; (ecx) = 8259 IRQ#
+; (al) = New Irql
+; (ebx) = Current Irql
+;
+
+ mov eax, 1
+ add ecx, 4 ; (ecx) = Irq # + 4
+ shl eax, cl
+ or PCR[PcIRR], eax
+
+;
+; Raise Irql to prevent it from happening again
+;
+
+;
+; Get the PIC masks for Irql
+;
+
+ mov eax, KiI8259MaskTable[ebx*4]
+ or eax, PCR[PcIDR]
+;
+; Write the new interrupt mask register back to the 8259
+;
+ SET_8259_MASK
+
+Hbsi390:
+
+ifdef IRQL_METRICS
+ lock inc HalPostponedIntCount
+endif
+
+ xor eax, eax ; return FALSE, spurious interrupt
+ stdRET _HalBeginSystemInterrupt
+
+
+HalpDismissIrq0fLevel:
+;
+; Check to see if this is a spurious interrupt
+;
+ mov al, OCW3_READ_ISR ; tell 8259 we want to read ISR
+ out PIC2_PORT0, al
+ IODelay ; delay
+ in al, PIC2_PORT0 ; (al) = content of PIC 1 ISR
+ test al, 10000000B ; Is In-Service register set?
+ jnz short HalpDismissLevel ; No, this is NOT a spurious int,
+ ; go do the normal interrupt stuff
+ jmp HalpIrq0fSpurious
+
+HalpDismissIrq07Level:
+;
+; Check to see if this is a spurious interrupt
+;
+ mov al, OCW3_READ_ISR ; tell 8259 we want to read ISR
+ out PIC1_PORT0, al
+ IODelay ; delay
+ in al, PIC1_PORT0 ; (al) = content of PIC 1 ISR
+ test al, 10000000B ; Is In-Service register set?
+ jnz short HalpDismissLevel ; No, so this is NOT a spurious int
+ mov eax, 0 ; return FALSE
+ stdRET _HalBeginSystemInterrupt
+
+HalpDismissIrq0dLevel:
+;
+; Clear the NPX busy latch.
+;
+
+ xor al,al
+ out I386_80387_BUSY_PORT, al
+
+align 4
+HalpDismissLevel:
+;
+; Mask this level interrupt off
+; (ecx) = 8259 IRQ#
+;
+ mov al, HbsiIrql ; (al) = New irql
+ mov eax, KiI8259MaskTable[eax*4] ; get 8259's masks
+ or eax, PCR[PcIDR] ; mask disabled irqs
+ SET_8259_MASK ; send mask to 8259s
+;
+; The SWInterruptHandler for this vector has been set to a NOP.
+; Set the vector's IRR so that Lower Irql will clear the 8259 mask for this
+; Irq when the irql is lowered below this level.
+;
+ mov eax, ecx ; (eax) = Irq #
+ mov ebx, 1
+ add ecx, 4 ; (ecx) = Irq # + 4
+ shl ebx, cl
+ or PCR[PcIRR], ebx
+
+;
+; Dismiss interrupt. Current interrupt is already masked off.
+; Then check to make sure the Irql of this interrupt > current Irql.
+; If it is not, we dismiss it as spurious - since this is a level interrupt
+; when the 8259's are unmasked the interrupt will reoccur
+;
+ mov cl, HbsiIrql
+ mov bl, PCR[PcIrql]
+ mov edx, HbsiOldIrql
+
+ cmp eax, 8 ; EOI to master or slave?
+ jae short Hbsi450 ; EIO to both master and slave
+
+ or al, PIC1_EOI_MASK ; create specific eoi mask for master
+ out PIC1_PORT0, al ; dismiss the interrupt
+
+ cmp cl, bl
+ jbe short Hbsi390 ; Spurious?
+
+ mov PCR[PcIrql], cl ; raise to new irql
+ mov byte ptr [edx], bl ; return old irql
+ sti
+ mov eax, 1 ; return TRUE
+ stdRET _HalBeginSystemInterrupt
+
+align 4
+Hbsi450:
+ add al, OCW2_SPECIFIC_EOI - 8 ; specific eoi to slave
+ out PIC2_PORT0, al
+ mov al, PIC2_EOI ; specific eoi to master for pic2 eoi
+ out PIC1_PORT0, al ; send irq2 specific eoi to master
+
+ cmp cl, bl
+ jbe Hbsi390 ; Spurious?
+
+ mov PCR[PcIrql], cl ; raise to new irql
+ mov byte ptr [edx], bl ; return old irql
+ sti
+ mov eax, 1 ; return TRUE
+ stdRET _HalBeginSystemInterrupt
+
+stdENDP _HalBeginSystemInterrupt
+
+
+;++
+;VOID
+;HalDisableSystemInterrupt(
+; IN CCHAR Vector,
+; IN KIRQL Irql
+; )
+;
+;
+;
+;Routine Description:
+;
+; Disables a system interrupt.
+;
+;Arguments:
+;
+; Vector - Supplies the vector of the interrupt to be disabled
+;
+; Irql - Supplies the interrupt level of the interrupt to be disabled
+;
+;Return Value:
+;
+; None.
+;
+;--
+cPublicProc _HalDisableSystemInterrupt ,2
+.FPO ( 0, 2, 0, 0, 0, 0 )
+
+;
+
+ movzx ecx, byte ptr [esp+4] ; (ecx) = Vector
+ sub ecx, PRIMARY_VECTOR_BASE ; (ecx) = 8259 irq #
+ mov edx, 1
+ shl edx, cl ; (ebx) = bit in IMR to disable
+ cli
+ or PCR[PcIDR], edx
+ xor eax, eax
+
+;
+; Get the current interrupt mask register from the 8259
+;
+ in al, PIC2_PORT1
+ shl eax, 8
+ in al, PIC1_PORT1
+;
+; Mask off the interrupt to be disabled
+;
+ or eax, edx
+;
+; Write the new interrupt mask register back to the 8259
+;
+ out PIC1_PORT1, al
+ shr eax, 8
+ out PIC2_PORT1, al
+ PIC2DELAY
+
+ sti
+ stdRET _HalDisableSystemInterrupt
+
+stdENDP _HalDisableSystemInterrupt
+
+;++
+;
+;BOOLEAN
+;HalEnableSystemInterrupt(
+; IN ULONG Vector,
+; IN KIRQL Irql,
+; IN KINTERRUPT_MODE InterruptMode
+; )
+;
+;
+;Routine Description:
+;
+; Enables a system interrupt
+;
+;Arguments:
+;
+; Vector - Supplies the vector of the interrupt to be enabled
+;
+; Irql - Supplies the interrupt level of the interrupt to be enabled.
+;
+;Return Value:
+;
+; None.
+;
+;--
+cPublicProc _HalEnableSystemInterrupt ,3
+.FPO ( 0, 3, 0, 0, 0, 0 )
+
+ movzx ecx, byte ptr [esp+4] ; (ecx) = vector
+ sub ecx, PRIMARY_VECTOR_BASE
+ jc hes_error
+ cmp ecx, CLOCK2_LEVEL
+ jnc hes_error
+
+;
+; If this interrupt is mapped through ISA via the PCI bus then it's
+; a level interrupt - treat it as such.
+;
+ bt _PciIsaIrq, ecx
+ jnc short @f
+
+;
+; It's OK to treat a level interrupt as an edge interrupt (just a performance
+; slow-down), but it's not OK to treat an edge interrupt as a level interrupt.
+; if the driver didn't say it's level, treat it as an edge
+;
+
+ mov al, [esp+12]
+ cmp al, 0
+ jnz short @f
+
+ mov SWInterruptHandlerTable+4*4[ecx*4], offset HalpHardwareInterruptLevel
+
+ mov edx, HalpSpecialDismissLevelTable[ecx*4]
+ mov HalpSpecialDismissTable[ecx*4], edx
+
+@@:
+ mov eax, 1
+ shl eax, cl ; (ebx) = bit in IMR to enable
+ not eax
+
+ cli
+ and PCR[PcIDR], eax
+
+;
+; Get the PIC masks for Irql 0
+;
+ mov eax, KiI8259MaskTable[0]
+ or eax, PCR[PcIDR]
+;
+; Write the new interrupt mask register back to the 8259
+;
+ SET_8259_MASK
+
+ sti
+ mov eax, 1 ; return TRUE
+ stdRET _HalEnableSystemInterrupt
+
+hes_error:
+if DBG
+ int 3
+endif
+ xor eax, eax ; FALSE
+ stdRET _HalEnableSystemInterrupt
+
+stdENDP _HalEnableSystemInterrupt
+
+
+_TEXT$01 ENDS
+
+ END
diff --git a/private/ntos/nthals/halx86/i386/ixthunk.c b/private/ntos/nthals/halx86/i386/ixthunk.c
new file mode 100644
index 000000000..d365f1933
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixthunk.c
@@ -0,0 +1,82 @@
+/*++
+
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ ixthunk.c
+
+Abstract:
+
+ This module contains the standard call routines which thunk to
+ fastcall routines.
+
+Author:
+
+ Ken Reneris (kenr) 04-May-1994
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "halp.h"
+
+#ifdef KeRaiseIrql
+#undef KeRaiseIrql
+#endif
+
+VOID
+KeRaiseIrql (
+ IN KIRQL NewIrql,
+ OUT PKIRQL OldIrql
+ )
+{
+ *OldIrql = KfRaiseIrql (NewIrql);
+}
+
+
+#ifdef KeLowerIrql
+#undef KeLowerIrql
+#endif
+
+
+VOID
+KeLowerIrql (
+ IN KIRQL NewIrql
+ )
+{
+ KfLowerIrql (NewIrql);
+}
+
+#ifdef KeAcquireSpinLock
+#undef KeAcquireSpinLock
+#endif
+
+VOID
+KeAcquireSpinLock (
+ IN PKSPIN_LOCK SpinLock,
+ OUT PKIRQL OldIrql
+ )
+{
+ *OldIrql = KfAcquireSpinLock (SpinLock);
+}
+
+
+#ifdef KeReleaseSpinLock
+#undef KeReleaseSpinLock
+#endif
+
+VOID
+KeReleaseSpinLock (
+ IN PKSPIN_LOCK SpinLock,
+ IN KIRQL NewIrql
+ )
+{
+ KfReleaseSpinLock (SpinLock, NewIrql);
+}
diff --git a/private/ntos/nthals/halx86/i386/ixusage.c b/private/ntos/nthals/halx86/i386/ixusage.c
new file mode 100644
index 000000000..e0efb9b20
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixusage.c
@@ -0,0 +1,535 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ixusage.c
+
+Abstract:
+
+Author:
+
+ Ken Reneris (kenr)
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+
+
+//
+// Array to remember hal's IDT usage
+//
+
+extern ADDRESS_USAGE *HalpAddressUsageList;
+extern IDTUsage HalpIDTUsage[MAXIMUM_IDTVECTOR];
+extern WCHAR HalpSzSystem[];
+extern WCHAR HalpSzSerialNumber[];
+
+KAFFINITY HalpActiveProcessors;
+
+VOID
+HalpGetResourceSortValue (
+ IN PCM_PARTIAL_RESOURCE_DESCRIPTOR pRCurLoc,
+ OUT PULONG sortscale,
+ OUT PLARGE_INTEGER sortvalue
+ );
+
+VOID
+HalpReportSerialNumber (
+ VOID
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,HalpEnableInterruptHandler)
+#pragma alloc_text(INIT,HalpRegisterVector)
+#pragma alloc_text(INIT,HalpGetResourceSortValue)
+#pragma alloc_text(INIT,HalpReportResourceUsage)
+#pragma alloc_text(INIT,HalpReportSerialNumber)
+#endif
+
+
+
+
+VOID
+HalpEnableInterruptHandler (
+ IN UCHAR ReportFlags,
+ IN ULONG BusInterruptVector,
+ IN ULONG SystemInterruptVector,
+ IN KIRQL SystemIrql,
+ IN VOID (*HalInterruptServiceRoutine)(VOID),
+ IN KINTERRUPT_MODE InterruptMode
+ )
+/*++
+
+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
+ //
+ HalpRegisterVector (ReportFlags, BusInterruptVector, SystemInterruptVector, SystemIrql);
+
+
+ //
+ // Connect the IDT and enable the vector now
+ //
+
+ KiSetHandlerAddressToIDT(SystemInterruptVector, HalInterruptServiceRoutine);
+ HalEnableSystemInterrupt(SystemInterruptVector, SystemIrql, InterruptMode);
+}
+
+
+
+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, pTPartList;
+ 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;
+
+ //
+ // Make sure all vectors 00-2f are reserved
+ // 00-1E reserved by Intel
+ // 1F reserved by Intel for APIC (apc priority level)
+ // 20-2e reserved by Microsoft
+ // 2f reserved by Microsoft for APIC (dpc priority level)
+ //
+
+ for(i=0; i < PRIMARY_VECTOR_BASE; 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;
+ }
+
+
+ pRPartList->Count++;
+ 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);
+
+ //
+ // Add system's serial number
+ //
+
+ HalpReportSerialNumber ();
+}
+
+VOID
+HalpReportSerialNumber (
+ VOID
+ )
+{
+ OBJECT_ATTRIBUTES objectAttributes;
+ UNICODE_STRING unicodeString;
+ HANDLE hSystem;
+ NTSTATUS status;
+
+ if (!HalpSerialLen) {
+ return ;
+ }
+
+ //
+ // Open HKEY_LOCAL_MACHINE\Hardware\Description\System
+ //
+
+ RtlInitUnicodeString (&unicodeString, HalpSzSystem);
+ InitializeObjectAttributes (
+ &objectAttributes,
+ &unicodeString,
+ OBJ_CASE_INSENSITIVE,
+ NULL, // handle
+ NULL
+ );
+
+
+ status = ZwOpenKey (&hSystem, KEY_READ | KEY_WRITE, &objectAttributes);
+ if (NT_SUCCESS(status)) {
+
+ //
+ // Add "Serial Number" as REG_BINARY
+ //
+
+ RtlInitUnicodeString (&unicodeString, HalpSzSerialNumber);
+
+ ZwSetValueKey (
+ hSystem,
+ &unicodeString,
+ 0L,
+ REG_BINARY,
+ HalpSerialNumber,
+ HalpSerialLen
+ );
+
+ ZwClose (hSystem);
+ }
+}
diff --git a/private/ntos/nthals/halx86/i386/ncrdetct.c b/private/ntos/nthals/halx86/i386/ncrdetct.c
new file mode 100644
index 000000000..2baf83ffa
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ncrdetct.c
@@ -0,0 +1,253 @@
+/*++
+
+Copyright (c) 1992 NCR Corporation
+
+Module Name:
+
+ ncrdetect.c
+
+Abstract:
+
+Authors:
+
+ Richard Barton (o-richb) 24-Jan-1992
+ Brian Weischedel 30-Nov-1992
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#ifndef _NTOS_
+#include "nthal.h"
+#endif
+
+PVOID
+HalpMapPhysicalMemory(
+ IN PVOID PhysicalAddress,
+ IN ULONG NumberPages
+ );
+
+VOID
+ReadCMOS(
+ IN ULONG StartingOffset,
+ IN ULONG Count,
+ IN PUCHAR ReturnValuePtr);
+
+ULONG NCRPlatform;
+
+#define NCR3450 0x35333433 // Copied here to build standalone
+#define NCR3550 0x30353834
+#define NCR3360 0x33333630
+
+// WPD definitions:
+
+PUCHAR WPDStringID = "NCR Voyager-1";
+PUCHAR WPDPlatformName = "System 3360";
+#define WPDStringIDLength 13
+#define WPDStringIDRangeStart (0xE000 << 4) // physical address
+#define WPDStringIDRangeSize 0x10000 // 1 segment (64k)
+
+// MSBU definitions:
+
+PUCHAR MSBUCopyrightString = "Copyright (C) ???? NCR\0";
+#define MSBUCopyrightStringLen 23
+#define MSBUCopyrightPhysicalPtr ((0xF000 << 4) + (0xE020))
+typedef struct {
+ ULONG ClassFromFirmware;
+ PUCHAR PlatformName;
+} MSBUPlatformMapEntry;
+MSBUPlatformMapEntry MSBUPlatformMap[] = {{NCR3450, "System 3450"},
+ {NCR3550, "System 3550"},
+ {0, 0}};
+
+PUCHAR
+NCRDeterminePlatform(
+ OUT PBOOLEAN IsConfiguredMp
+)
+/*++
+
+Routine Description:
+ Determine on which NCR platform we are running. For now just display
+ a message. Later we may not continue the boot if we're on an
+ unrecognized platform.
+
+Arguments:
+ none.
+
+Return Value:
+ Pointer to character string identifying which NCR platform. NULL means
+ it is unrecognized, and we shouldn't continue.
+
+--*/
+{
+ BOOLEAN Matchfound;
+ MSBUPlatformMapEntry *MSBUPlatformMapPtr;
+ PVOID BIOSPagePtr;
+ PUCHAR StringPtr;
+ PUCHAR CopyrightPtr;
+ PUCHAR SearchPtr;
+ UCHAR CpuFlags;
+
+
+ // first check for a WPD platform by searching the 0xE000 BIOS segment
+ // for a ROM string that identifies this system as a 3360
+
+
+ // get virtual address to the BIOS region (assuming region is both
+ // page aligned and multiple pages in size)
+
+ BIOSPagePtr = HalpMapPhysicalMemory((PVOID) WPDStringIDRangeStart,
+ (WPDStringIDRangeSize >> 12));
+
+ if (BIOSPagePtr != NULL) {
+
+ SearchPtr = BIOSPagePtr; // begin search at start of region
+ Matchfound = FALSE;
+
+ // search until string is found or we are beyond the region
+
+ while (!Matchfound && (SearchPtr <= (PUCHAR)((ULONG)BIOSPagePtr +
+ WPDStringIDRangeSize -
+ WPDStringIDLength))) {
+
+ // see if SearchPtr points to the desired string
+
+ StringPtr = (PUCHAR)((ULONG)SearchPtr++);
+ CopyrightPtr = WPDStringID;
+
+ // continue compare as long as characters compare
+ // and not at end of string
+
+ while ((Matchfound = (*CopyrightPtr++ == *StringPtr++)) &&
+ (CopyrightPtr < WPDStringID + WPDStringIDLength));
+ }
+
+ // see if string was found (i.e., if this is a 3360)
+
+ if (Matchfound) {
+
+ // store system identifier ("3360") for later HAL use
+
+ NCRPlatform = NCR3360;
+
+ // read CPU good flags from CMOS and determine if MP
+
+ ReadCMOS(0x88A, 1, &CpuFlags);
+ // *IsConfiguredMp = (CpuFlags & (CpuFlags-1)) ? TRUE : FALSE;
+
+ // This is an MP hal
+ *IsConfiguredMp = TRUE;
+
+ return(WPDPlatformName);
+ }
+
+ }
+
+
+ // now check for an MSBU platform
+
+
+ /*
+ * Map in the BIOS text so we can look for our copyright string.
+ */
+ BIOSPagePtr = (PVOID)((ULONG)MSBUCopyrightPhysicalPtr &
+ ~(PAGE_SIZE - 1));
+ BIOSPagePtr = HalpMapPhysicalMemory(BIOSPagePtr, 2);
+ if (BIOSPagePtr == NULL)
+ return(NULL);
+
+ StringPtr = (PUCHAR)((ULONG)BIOSPagePtr +
+ ((ULONG)MSBUCopyrightPhysicalPtr & (PAGE_SIZE - 1)))
+ + (MSBUCopyrightStringLen - 1);
+ CopyrightPtr = MSBUCopyrightString + (MSBUCopyrightStringLen - 1);
+ do {
+ Matchfound = ((*CopyrightPtr == '?') ||
+ (*CopyrightPtr == *StringPtr));
+ --CopyrightPtr;
+ --StringPtr;
+ } while (Matchfound && (CopyrightPtr >= MSBUCopyrightString));
+
+ //
+ // /*
+ // * Clear the mapping to BIOS. We mapped in two pages.
+ // */
+ // BIOSPagePtr = MiGetPteAddress(BIOSPagePtr);
+ // *(PULONG)BIOSPagePtr = 0;
+ // *(((PULONG)BIOSPagePtr)+1) = 0;
+ // /*
+ // * Flush the TLB.
+ // */
+ // _asm {
+ // mov eax, cr3
+ // mov cr3, eax
+ // }
+ //
+
+ if (Matchfound) {
+ /*
+ * must be an MSBU machine..determine which.
+ */
+ ReadCMOS(0xB16, 4, (PUCHAR)&NCRPlatform);
+ for (MSBUPlatformMapPtr = MSBUPlatformMap;
+ (MSBUPlatformMapPtr->ClassFromFirmware != 0);
+ ++MSBUPlatformMapPtr) {
+ if (MSBUPlatformMapPtr->ClassFromFirmware ==
+ NCRPlatform) {
+
+ *IsConfiguredMp = TRUE;
+ return(MSBUPlatformMapPtr->PlatformName);
+ }
+ }
+
+ /*
+ * prerelease version of firmware had this machine class
+ * at the wrong offset into CMOS. until all those versions
+ * of firmware are extinguished from the face of the earth
+ * we should recognize them with this:
+ */
+ ReadCMOS(0xAB3, 4, (PUCHAR)&NCRPlatform);
+ for (MSBUPlatformMapPtr = MSBUPlatformMap;
+ (MSBUPlatformMapPtr->ClassFromFirmware != 0);
+ ++MSBUPlatformMapPtr) {
+ if (MSBUPlatformMapPtr->ClassFromFirmware ==
+ NCRPlatform) {
+ *IsConfiguredMp = TRUE;
+ return(MSBUPlatformMapPtr->PlatformName);
+ }
+ }
+ }
+
+ return(NULL);
+}
+
+
+#ifndef SETUP // if built with Hal, must provide ReadCMOS routine
+
+ULONG
+HalpGetCmosData (
+ IN ULONG SourceLocation,
+ IN ULONG SourceAddress,
+ IN PUCHAR Buffer,
+ IN ULONG Length);
+
+VOID
+ReadCMOS(
+ IN ULONG StartingOffset,
+ IN ULONG Count,
+ IN PUCHAR ReturnValuePtr
+)
+/*++
+
+Routine Description:
+ This routine simply converts a ReadCMOS call (a routine in setup) to
+ the corresponding routine provided in the Hal (HalpGetCmosData).
+
+--*/
+{
+ HalpGetCmosData(1, StartingOffset, ReturnValuePtr, Count);
+}
+#endif
diff --git a/private/ntos/nthals/halx86/i386/pcip.h b/private/ntos/nthals/halx86/i386/pcip.h
new file mode 100644
index 000000000..c5f09f2e5
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/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/halx86/i386/xxbiosa.asm b/private/ntos/nthals/halx86/i386/xxbiosa.asm
new file mode 100644
index 000000000..e3d5493b6
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/xxbiosa.asm
@@ -0,0 +1,712 @@
+;++
+;
+; Copyright (c) 1991 Microsoft Corporation
+;
+; Module Name:
+;
+; xxbiosa.asm
+;
+; Abstract:
+;
+; This implements the necessary code to put the processor into
+; V86 mode, make a BIOS call, and return safely to protected mode.
+;
+; Author:
+;
+; John Vert (jvert) 29-Oct-1991
+;
+; Environment:
+;
+; Kernel mode
+;
+; Notes:
+;
+; This module is intended for use in panic situations, such as a bugcheck.
+; As a result, we cannot rely on the integrity of the system so we must
+; handle everything ourselves. Notably, we must map our own memory by
+; adding our own page tables and PTEs.
+;
+; We also cannot call KeBugCheck when we notice something has gone wrong.
+;
+; Revision History:
+;
+;--
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+include i386\kimacro.inc
+ .list
+
+ extrn _DbgPrint:proc
+ EXTRNP _DbgBreakPoint,0,IMPORT
+ EXTRNP Kei386EoiHelper,0,IMPORT
+
+ public _HalpRealModeStart
+ public _HalpRealModeEnd
+;
+; 32-bit override
+;
+OVERRIDE equ 66h
+
+;
+; Reginfo structure
+;
+
+RegInfo struc
+RiSegSs dd 0
+RiEsp dd 0
+RiEFlags dd 0
+RiSegCs dd 0
+RiEip dd 0
+RiTrapFrame dd 0
+RiCsLimit dd 0
+RiCsBase dd 0
+RiCsFlags dd 0
+RiSsLimit dd 0
+RiSsBase dd 0
+RiSsFlags dd 0
+RiPrefixFlags dd 0
+RegInfo ends
+REGINFOSIZE EQU 52
+
+INT_NN_OPCODE EQU 0CDH
+
+ page ,132
+_DATA SEGMENT DWORD PUBLIC 'DATA'
+
+;
+; In order to return to the calling function after we've trapped out of
+; V86 mode, we save our ESP value here.
+;
+HalpSavedEsp dd 0
+
+_DATA ENDS
+
+
+_TEXT SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:NOTHING, ES:NOTHING, SS:FLAT, FS:NOTHING, GS:NOTHING
+
+if DBG
+ page ,132
+ subttl "Processing Exception occurred in ABIOS code"
+;++
+; VOID
+; KiAbiosException (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This routine is called after an exception being detected
+; in ABIOS ROM code. The system will switch 16 stack to 32 bit
+; stack and bugcheck.
+;
+; N.B. In fact this routine is simply used to resolve a reference
+; to KiAbiosException routine in the Kimacro.inc ENTER_TRAP
+; macro.
+;
+;
+; Arguments:
+;
+; None.
+;
+; Return value:
+;
+; system stopped.
+;
+;--
+ public _KiAbiosException
+_KiAbiosException proc
+_Ki16BitStackException:
+ ret
+
+_KiAbiosException endp
+
+endif
+
+
+;++
+; ULONG
+; HalpBorrowTss (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This routine checks if the current TSS has IO MAP space.
+; if yes, it simply returns. Otherwise, it switches to use
+; the regular TSS.
+;
+; Arguments:
+;
+; None.
+;
+; Return value:
+;
+; Return original TSS selector if the regular Tss is borrowed by us.
+;
+;--
+cPublicProc _HalpBorrowTss, 0
+cPublicFpo 0, 0
+
+ xor eax, eax
+ str ax
+ mov edx, PCR[PcGdt]
+ add edx, eax ; (edx)->Gdt Entry of current
+ ; TSS
+ xor ecx, ecx
+ mov cl, [edx].KgdtLimitHi
+ shl ecx, 16
+ mov cx, [edx].KgdtLimitLow ; (ecx) = TSS limit
+ cmp ecx, 2000H ; Is Io map space available?
+ ja short Hbt99 ; if a, yes, return
+
+ sub edx, eax ; (edx)->GDT table
+ mov ch, [edx+KGDT_TSS+KgdtBaseHi]
+ mov cl, [edx+KGDT_TSS+KgdtBaseMid]
+ shl ecx, 16
+ mov cx, [edx+KGDT_TSS+KgdtBaseLow]
+ mov PCR[PcTss], ecx
+ mov ecx, KGDT_TSS ; switch to use regular TSS
+ mov byte ptr [edx+KGDT_TSS+5], 089h ; 32bit, dpl=0, present, TSS32,
+ ; not busy.
+ ltr cx
+ stdRET _HalpBorrowTss ; (eax) = Original TSS sel
+
+Hbt99:
+ xor eax, eax ; No TSS swapped
+ stdRET _HalpBorrowTss
+
+stdENDP _HalpBorrowTss
+
+
+;++
+; VOID
+; HalpReturnTss (
+; ULONG TssSelector
+; )
+;
+; Routine Description:
+;
+; This routine switches the current TSS from regular TSS back to
+; the panic TSS (NMI TSS or Double fault TSS).
+;
+; Arguments:
+;
+; TssSelector - the TSS selector to return to.
+;
+; Return value:
+;
+; None.
+;
+;--
+cPublicProc _HalpReturnTss, 1
+cPublicFpo 1, 0
+
+ mov edx, PCR[PcGdt] ; (edx)-> Gdt table
+ mov eax, [esp + 4]
+ and eax, 0FFFFh ; (eax)= New TSS sel
+ add edx, eax ; (edx)->Gdt Entry of new TSS
+
+ mov ch, [edx+KgdtBaseHi]
+ mov cl, [edx+KgdtBaseMid]
+ shl ecx, 16
+ mov cx, [edx+KgdtBaseLow]
+ mov PCR[PcTss], ecx
+ mov byte ptr [edx+5], 089h ; 32bit, dpl=0, present, TSS32,
+ ltr ax
+ stdRET _HalpReturnTss ; return and clear stack
+
+stdENDP _HalpReturnTss
+
+;++
+;
+; VOID
+; HalpBiosCall
+; VOID
+; )
+;
+; Routine Description:
+;
+; This routine completes the transition to real mode, calls BIOS, and
+; returns to protected mode.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; None.
+;
+;--
+;;ALIGN 4096
+cPublicProc _HalpBiosCall ,0
+
+ push ebp
+ mov ebp, esp
+ pushfd
+ push edi
+ push esi
+ push ebx
+ push ds
+ push es
+ push fs
+ push gs
+ push offset FLAT:HbcProtMode ; address where we will start
+ ; protected mode again once
+ ; V86 has completed.
+ mov HalpSavedEsp, esp
+
+ mov eax, cr0 ; make sure alignment
+ and eax, not CR0_AM ; checks are disabled
+ mov cr0, eax
+
+;
+; Create space for the V86 trap frame and update the ESP0 value in the TSS
+; to use this space. We will set this up just below our current stack pointer.
+; The stuff we push on the stack after we set ESP0 is irrelevant once we
+; make it to V86 mode, so it's ok to blast it.
+;
+ mov esi, fs:PcTss ; (esi) -> TSS
+ mov eax, esp
+ sub eax, NPX_FRAME_LENGTH ; skip FP save area
+ mov [esi]+TssEsp0, eax
+
+ push dword ptr 0h ; V86 GS
+ push dword ptr 0h ; V86 FS
+ push dword ptr 0h ; V86 DS
+ push dword ptr 0h ; V86 ES
+ push dword ptr 2000h ; V86 SS
+
+;
+; We calculate the V86 sp by adding the difference between the linear address
+; of the V86 ip (HbcReal) and the linear address of the V86 sp (HbcV86Stack)
+; to the offset of the V86 ip (HbcReal & 0xfff).
+;
+
+ mov eax, offset FLAT:HbcV86Stack-4
+ sub eax, offset FLAT:HbcReal
+ mov edx, offset HbcReal
+ and edx, 0fffh
+ add eax, edx
+ push eax ; V86 esp
+
+ pushfd
+ or dword ptr [esp], EFLAGS_V86_MASK; V86 eflags
+ or [esp], 03000h ; Give IOPL3
+ push dword ptr 2000h ; V86 CS
+ mov eax, offset HbcReal
+ and eax, 0fffh
+
+ push edx ; V86-mode EIP is offset
+ ; into CS.
+ iretd
+
+_HalpRealModeStart label byte
+
+HbcReal:
+ db OVERRIDE ; make mov 32-bits
+ mov eax, 03h ; 80x25 mode, 16 colors
+ int 10h
+
+ db OVERRIDE ; make mov 32-bits
+ mov eax, 1112h ; use 8x8 font (causes 50 line mode)
+ db OVERRIDE
+ mov ebx, 0
+ int 10h
+
+ db 0c4h, 0c4h ; BOP to indicate V86 mode is done.
+
+;
+; V86-mode stack
+;
+align 4
+ db 2048 dup(0)
+HbcV86Stack:
+
+_HalpRealModeEnd label byte
+
+HbcProtMode:
+;
+; We are back from V86 mode, so restore everything we saved and we are done.
+;
+ pop gs
+ pop fs
+ pop es
+ pop ds
+ pop ebx
+ pop esi
+ pop edi
+ popfd
+ pop ebp
+ stdRET _HalpBiosCall
+
+ public _HalpBiosCallEnd
+_HalpBiosCallEnd label byte
+
+
+
+_HalpBiosCall endp
+
+
+ subttl "HAL General Protection Fault"
+;++
+;
+; Routine Description:
+;
+; Handle General protection fault.
+;
+; This fault handler is used by the HAL for V86 mode faults only.
+; It should NEVER be used except when running in V86 mode. The HAL
+; replaces the general-purpose KiTrap0D handler entry in the IDT with
+; this routine. This allows us to emulate V86-mode instructions which
+; cause a fault. After we return from V86 mode, we can restore the
+; KiTrap0D handler in the IDT.
+;
+; Arguments:
+;
+; At entry, the saved CS:EIP point to the faulting instruction
+; Error code (whose value depends on detected condition) is provided.
+;
+; Return value:
+;
+; None
+;
+;--
+ ASSUME DS:FLAT, SS:NOTHING, ES:FLAT
+
+ ENTER_DR_ASSIST Htd_a, Htd_t, NoAbiosAssist
+cPublicProc _HalpTrap0D ,0
+
+ ENTER_TRAP Htd_a, Htd_t
+
+;
+; Did the trap occur in V86 mode? If not, something is completely screwed.
+;
+ test dword ptr [ebp]+TsEFlags,00020000H
+ jnz Ht0d10
+
+;
+; The trap was not from V86 mode, so something is very wrong. We cannot
+; BugCheck, since we are probably already in a BugCheck. So just stop.
+;
+
+if DBG
+_DATA segment
+MsgBadHalTrap db 'HAL: Trap0D while not in V86 mode',0ah,0dh,0
+_DATA ends
+
+ push offset FLAT:MsgBadHalTrap
+ call _DbgPrint
+ add esp,4
+ stdCall _DbgBreakPoint
+endif
+;
+; We can't bugcheck, so just commit suicide. Maybe we should reboot?
+;
+ jmp $
+
+Ht0d10:
+ stdCall HalpDispatchV86Opcode
+ SPURIOUS_INTERRUPT_EXIT
+stdENDP _HalpTrap0d
+
+ subttl "HAL Invalid Opcode Fault"
+;++
+;
+; Routine Description:
+;
+; Handle invalid opcode fault
+;
+; This fault handler is used by the HAL to indicate when V86 mode
+; execution is finished. The V86 code attempts to execute an invalid
+; instruction (BOP) when it is done, and that brings us here.
+; This routine just removes the trap frame from the stack and does
+; a RET. Note that this assumes that ESP0 in the TSS has been set
+; up to point to the top of the stack that we want to be running on
+; when the V86 call has completed.
+;
+; This should NEVER be used except when running in V86 mode. The HAL
+; replaces the general-purpose KiTrap06 handler entry in the IDT with
+; this routine. It also sets up ESP0 in the TSS appropriately. After
+; the V86 call has completed, it restores these to their previous values.
+;
+; Arguments:
+;
+; At entry, the saved CS:EIP point to the faulting instruction
+; Error code (whose value depends on detected condition) is provided.
+;
+; Return value:
+;
+; None
+;
+;--
+ ASSUME DS:FLAT, SS:NOTHING, ES:FLAT
+
+cPublicProc _HalpTrap06 ,0
+ mov eax,KGDT_R3_DATA OR RPL_MASK
+ mov ds,ax
+ mov es,ax
+ mov esp, HalpSavedEsp
+ ret
+
+stdENDP _HalpTrap06
+
+ subttl "Instruction Emulation Dispatcher"
+;++
+;
+; Routine Description:
+;
+; This routine dispatches to the opcode specific emulation routine,
+; based on the first byte of the opcode. Two byte opcodes, and prefixes
+; result in another level of dispatching, from the handling routine.
+;
+; This code blatantly stolen from ke\i386\instemul.asm
+;
+; Arguments:
+;
+; ebp = pointer to trap frame
+;
+; Returns:
+;
+; Nothing
+;
+
+cPublicProc HalpDispatchV86Opcode ,0
+
+RI equ [ebp - REGINFOSIZE]
+ push ebp
+ mov ebp,esp
+ sub esp,REGINFOSIZE
+ push esi
+ push edi
+
+ ; Initialize RegInfo
+
+ mov esi,[ebp]
+ mov RI.RiTrapFrame,esi
+ movzx eax,word ptr [esi].TsHardwareSegSs
+ mov RI.RiSegSs,eax
+ mov eax,[esi].TsHardwareEsp
+ mov RI.RiEsp,eax
+ mov eax,[esi].TsEFlags
+ mov RI.RiEFlags,eax
+ movzx eax,word ptr [esi].TsSegCs
+ mov RI.RiSegCs,eax
+ mov eax,[esi].TsEip
+ mov RI.RiEip,eax
+
+ xor eax,eax
+ mov RI.RiPrefixFlags,eax
+ lea esi,RI
+
+;
+; Convert CS to a linear address
+;
+
+ mov eax,[esi].RiSegCs
+ shl eax,4
+ mov [esi].RiCsBase,eax
+ mov [esi].RiCsLimit,0FFFFh
+ mov [esi].RiCsFlags,0
+
+ mov edi,RI.RiEip
+ cmp edi,RI.RiCsLimit
+ ja doerr
+
+ add edi,RI.RiCsBase
+ mov dl, [edi] ; get faulting opcode
+ cmp dl, INT_NN_OPCODE
+ je short @f
+
+ stdCall HalpOpcodeInvalid
+ jmp short doerr
+
+@@:
+ stdCall HalpOpcodeINTnn
+ test eax,0FFFFh
+ jz do20
+
+ mov edi,RI.RiTrapFrame
+ mov eax,RI.RiEip ; advance eip
+ mov [edi].TsEip,eax
+ mov eax,1
+do20: pop edi
+ pop esi
+ mov esp,ebp
+ pop ebp
+ ret
+
+doerr: xor eax,eax
+ jmp do20
+stdENDP HalpDispatchV86Opcode
+
+ page ,132
+ subttl "Invalid Opcode Handler"
+;++
+;
+; Routine Description:
+;
+; This routine handles invalid opcodes. It prints the invalid
+; opcode message, and breaks into the kernel debugger.
+;
+; Arguments:
+;
+; esi = address of reg info
+; edx = opcode
+;
+; Returns:
+;
+; nothing
+;
+
+cPublicProc HalpOpcodeInvalid ,0
+
+_DATA segment
+HalpMsgInvalidOpcode db 'HAL: An invalid V86 opcode was encountered at '
+ db 'address %x:%x',0ah, 0dh, 0
+_DATA ends
+
+ push [esi].RiEip
+ push [esi].RiSegCs
+ push offset FLAT:HalpMsgInvalidOpcode
+ call _DbgPrint ; display invalid opcode message
+ add esp,12
+ int 3
+ xor eax,eax
+ stdRET HalpOpcodeInvalid
+
+stdENDP HalpOpcodeInvalid
+
+ subttl "INTnn Opcode Handler"
+;++
+;
+; Routine Description:
+;
+; This routine emulates an INTnn opcode. It retrieves the handler
+; from the IVT, pushes the current cs:ip and flags on the stack,
+; and dispatches to the handler.
+;
+; Arguments:
+;
+; esi = address of reg info
+; edx = opcode
+;
+; Returns:
+;
+; Current CS:IP on user stack
+; RiCs:RiEip -> handler from IVT
+;
+
+cPublicProc HalpOpcodeINTnn ,0
+
+ push ebp
+ push edi
+ push ebx
+
+;
+; Convert SS to linear address
+;
+ mov eax,[esi].RiSegSs
+ shl eax,4
+ mov [esi].RiSsBase,eax
+ mov [esi].RiSsLimit,0FFFFh
+ mov [esi].RiSsFlags,0
+
+ inc [esi].RiEip ; point to int #
+ mov edi,[esi].RiEip
+ cmp edi,[esi].RiCsLimit
+ ja oinerr
+
+ add edi,[esi].RiCsBase
+ movzx ecx,byte ptr [edi] ; get int #
+ inc [esi].RiEip ; inc past end of instruction
+ stdCall HalpPushInt
+ test eax,0FFFFh
+ jz oin20 ; error!
+;
+; BugBug Some sort of check for BOP should go here, or in push int.
+;
+
+ mov ebp,[esi].RiTrapFrame
+ mov eax,[esi].RiSegSs
+ mov [ebp].TsHardwareSegSs,eax
+ mov eax,[esi].RiEsp
+ mov [ebp].TsHardwareEsp,eax
+ mov eax,[esi].RiSegCs
+ mov [ebp].TsSegCs,eax
+ mov eax,[esi].RiEFlags
+ mov [ebp].TsEFlags,eax
+ mov eax,1
+oin20: pop ebx
+ pop edi
+ pop ebp
+ stdRET HalpOpcodeINTnn
+
+oinerr: xor eax,eax
+ jmp oin20
+
+stdENDP HalpOpcodeINTnn
+
+ page ,132
+ subttl "Push Interrupt frame on user stack"
+;++
+;
+; Routine Description:
+;
+; This routine pushes an interrupt frame on the user stack
+;
+; Arguments:
+;
+; ecx = interrupt #
+; esi = address of reg info
+; Returns:
+;
+; interrupt frame pushed on stack
+; reg info updated
+;bugbug does this routine trash BX??
+;
+cPublicProc HalpPushInt ,0
+ push ebx
+
+ mov edx,[esi].RiEsp
+ mov ebx,[esi].RiSsBase
+ and edx,0FFFFh ; only use a 16 bit sp
+ sub dx,2
+ mov ax,word ptr [esi].RiEFlags
+ mov [ebx+edx],ax ; push flags
+ sub dx,2
+ mov ax,word ptr [esi].RiSegCs
+ mov [ebx+edx],ax ; push cs
+ sub dx,2
+ mov ax,word ptr [esi].RiEip
+ mov [ebx+edx],ax ; push ip
+ mov eax,[ecx*4] ; get new cs:ip value
+ push eax
+ movzx eax,ax
+ mov [esi].RiEip,eax
+ pop eax
+ shr eax,16
+ mov [esi].RiSegCs,eax
+ mov word ptr [esi].RiEsp,dx
+
+;
+; Convert CS to a linear address
+;
+
+ mov eax,[esi].RiSegCs
+ shl eax,4
+ mov [esi].RiCsBase,eax
+ mov [esi].RiCsLimit,0FFFFh
+ mov [esi].RiCsFlags,0
+
+ mov eax,1 ; success
+pi80: pop ebx
+ stdRET HalpPushInt
+stdENDP HalpPushInt
+
+
+_TEXT ends
+ end
diff --git a/private/ntos/nthals/halx86/i386/xxbiosc.c b/private/ntos/nthals/halx86/i386/xxbiosc.c
new file mode 100644
index 000000000..6b5f1cc69
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/xxbiosc.c
@@ -0,0 +1,299 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ xxbiosc.c
+
+Abstract:
+
+ This module implements the protect-mode routines necessary to make the
+ transition to real mode and return to protected mode.
+
+Author:
+
+ John Vert (jvert) 29-Oct-1991
+
+
+Environment:
+
+ Kernel mode only.
+ Probably a panic-stop, so we cannot use any system services.
+
+Revision History:
+
+--*/
+#include "halp.h"
+
+//
+// Function definitions
+//
+
+
+ULONG
+HalpBorrowTss(
+ VOID
+ );
+
+VOID
+HalpReturnTss(
+ ULONG TssSelector
+ );
+
+VOID
+HalpBiosCall(
+ VOID
+ );
+
+
+VOID
+HalpTrap06(
+ VOID
+ );
+
+
+VOID
+HalpTrap0D(
+ VOID
+ );
+
+VOID
+HalpBiosDisplayReset(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Calls BIOS by putting the machine into V86 mode. This involves setting up
+ a physical==virtual identity mapping for the first 1Mb of memory, setting
+ up V86-specific trap handlers, and granting I/O privilege to the V86
+ process by editing the IOPM bitmap in the TSS.
+
+Environment:
+
+ Interrupts disabled.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ HARDWARE_PTE OldPageTable;
+ USHORT OldIoMapBase;
+ ULONG OldEsp0;
+ PHARDWARE_PTE Pte;
+ PHARDWARE_PTE V86CodePte;
+ ULONG cnt;
+ ULONG OldTrap0DHandler;
+ ULONG OldTrap06Handler;
+ PUCHAR IoMap;
+ ULONG Virtual;
+// KIRQL OldIrql;
+ ULONG OriginalTssSelector;
+ extern PVOID HalpRealModeStart;
+ extern PVOID HalpRealModeEnd;
+PHARDWARE_PTE PointerPde;
+ULONG PageFrame;
+ULONG PageFrameEnd;
+
+ //
+ // Interrupts are off, but V86 mode might turn them back on again.
+ //
+ HalpDisableAllInterrupts ();
+
+ //
+ // We need to set up an identity mapping in the first page table. First,
+ // we save away the old page table.
+ //
+ OldPageTable = *MiGetPdeAddress(0);
+
+ //
+ // Now we put the HAL page table into the first slot of the page
+ // directory. Note that this page table is now the first and last
+ // entries in the page directory.
+ //
+ Pte = MiGetPdeAddress(0);
+ Pte->PageFrameNumber = MiGetPdeAddress(0xffc00000)->PageFrameNumber;
+ Pte->Valid = 1;
+ Pte->Write = 1;
+ Pte->Owner = 1; // User-accessible
+
+ //
+ // Flush TLB
+ //
+
+ HalpFlushTLB();
+
+ //
+ // Map the first 1Mb of virtual memory to the first 1Mb of physical
+ // memory
+ //
+ for (Virtual=0; Virtual < 0x100000; Virtual += PAGE_SIZE) {
+ Pte = MiGetPteAddress(Virtual);
+ Pte->PageFrameNumber = ((ULONG)Virtual >> PAGE_SHIFT);
+ Pte->Valid = 1;
+ Pte->Write = 1;
+ Pte->Owner = 1; // User-accessible
+ }
+
+ //
+ // Map our code into the virtual machine
+ //
+
+ Pte = MiGetPteAddress(0x20000);
+ PointerPde = MiGetPdeAddress(&HalpRealModeStart);
+
+ if ( PointerPde->LargePage ) {
+ //
+ // Map real mode PTEs into virtual mapping. The source PDE is
+ // from the indenity large pte map, so map the virtual machine PTEs
+ // based on the base of the large PDE frame.
+ //
+
+ PageFrame = ((ULONG)(&HalpRealModeStart) >> 12) & 0x3FF;
+ PageFrameEnd = ((ULONG)(&HalpRealModeEnd) >> 12) & 0x3FF;
+ do {
+
+ Pte->PageFrameNumber = PointerPde->PageFrameNumber + PageFrame;
+
+ ++Pte;
+ ++PageFrame;
+
+ } while (PageFrame <= PageFrameEnd);
+
+ } else {
+
+ //
+ // Map real mode PTEs into virtual machine PTEs, by copying the
+ // page frames from the source to the virtual machine PTEs.
+ //
+
+ V86CodePte = MiGetPteAddress(&HalpRealModeStart);
+ do {
+ Pte->PageFrameNumber = V86CodePte->PageFrameNumber;
+
+ ++Pte;
+ ++V86CodePte;
+
+ } while ( V86CodePte <= MiGetPteAddress(&HalpRealModeEnd) );
+
+ }
+ //
+ // Flush TLB
+ //
+
+ HalpFlushTLB();
+
+ //
+ // We need to replace the current TRAP D handler with our own, so
+ // we can do instruction emulation for V86 mode
+ //
+
+ OldTrap0DHandler = KiReturnHandlerAddressFromIDT(0xd);
+ KiSetHandlerAddressToIDT(0xd, HalpTrap0D);
+
+ OldTrap06Handler = KiReturnHandlerAddressFromIDT(6);
+ KiSetHandlerAddressToIDT(6, HalpTrap06);
+
+ //
+ // Make sure current TSS has IoMap space available. If no, borrow
+ // Normal TSS.
+ //
+
+ OriginalTssSelector = HalpBorrowTss();
+
+ //
+ // Overwrite the first access map with zeroes, so the V86 code can
+ // party on all the registers.
+ //
+ IoMap = (PUCHAR)&(KeGetPcr()->TSS->IoMaps[0]);
+
+ for (cnt=0; cnt<IOPM_SIZE; cnt++) {
+ IoMap[cnt] = 0;
+ }
+ for (cnt=IOPM_SIZE; cnt<PIOPM_SIZE; cnt++) {
+ IoMap[cnt] = 0xff;
+ }
+ OldIoMapBase = KeGetPcr()->TSS->IoMapBase;
+
+ KeGetPcr()->TSS->IoMapBase = KiComputeIopmOffset(1);
+
+ //
+ // Save the current ESP0, as HalpBiosCall() trashes it.
+ //
+ OldEsp0 = KeGetPcr()->TSS->Esp0;
+
+ //
+ // Call the V86-mode code
+ //
+ HalpBiosCall();
+
+ //
+ // Restore the TRAP handlers
+ //
+
+ KiSetHandlerAddressToIDT(0xd, OldTrap0DHandler);
+ KiSetHandlerAddressToIDT(6, OldTrap06Handler);
+
+ //
+ // Restore Esp0 value
+ //
+ KeGetPcr()->TSS->Esp0 = OldEsp0;
+
+ KeGetPcr()->TSS->IoMapBase = OldIoMapBase;
+
+ //
+ // Return borrowed TSS if any.
+ //
+
+ if (OriginalTssSelector != 0) {
+ HalpReturnTss(OriginalTssSelector);
+ }
+
+ //
+ // Unmap the first 1Mb of virtual memory
+ //
+ for (Virtual = 0; Virtual < 0x100000; Virtual += PAGE_SIZE) {
+ Pte = MiGetPteAddress(Virtual);
+ Pte->PageFrameNumber = 0;
+ Pte->Valid = 0;
+ Pte->Write = 0;
+ }
+
+ //
+ // Restore the original page table that we replaced.
+ //
+ *MiGetPdeAddress(0) = OldPageTable;
+
+ //
+ // Flush TLB
+ //
+
+ HalpFlushTLB();
+
+ //
+ // This function is only used during a system crash. We don't re-
+ // enable interrupts.
+ //
+ // KeLowerIrql(OldIrql);
+}
+
+HAL_DISPLAY_BIOS_INFORMATION
+HalpGetDisplayBiosInformation (
+ VOID
+ )
+{
+ // this hal uses native int-10
+
+ return HalDisplayInt10Bios;
+}
+
diff --git a/private/ntos/nthals/halx86/i386/xxdisp.c b/private/ntos/nthals/halx86/i386/xxdisp.c
new file mode 100644
index 000000000..5806751fc
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/xxdisp.c
@@ -0,0 +1,476 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ xxdisp.c
+
+Abstract:
+
+ This module implements the HAL display initialization and output routines
+ for a x86 system.
+
+Author:
+
+ David N. Cutler (davec) 27-Apr-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+
+//
+// Private function prototypes
+//
+VOID
+HalpClearDisplay(
+ VOID
+ );
+
+VOID
+HalpNextLine(
+ VOID
+ );
+
+VOID
+HalpScrollDisplay(
+ VOID
+ );
+
+VOID
+HalpPutCharacter(
+ IN UCHAR Character
+ );
+
+#define REVERSE_ATTRIBUTE 0x17
+#define ROWS 50
+#define COLS 80
+
+ULONG HalpCursorX=0;
+ULONG HalpCursorY=0;
+
+KSPIN_LOCK HalpDisplayLock;
+
+
+PUSHORT VideoBuffer;
+
+//
+// If someone calls HalDisplayString before HalInitSystem, we need to be
+// able to put something up on screen anyway.
+//
+BOOLEAN HalpDisplayInitialized=FALSE;
+
+//
+// This is how we tell if GDI has taken over the display. If so, we are
+// in graphics mode and we need to reset the display to text mode before
+// displaying anything. (Panic stop)
+//
+BOOLEAN HalpOwnsDisplay=TRUE;
+PHAL_RESET_DISPLAY_PARAMETERS HalpResetDisplayParameters;
+
+BOOLEAN HalpDoingCrashDump = FALSE;
+
+
+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.
+
+--*/
+
+{
+ HalpResetDisplayParameters=ResetDisplayParameters;
+ HalpOwnsDisplay=FALSE;
+ return;
+}
+
+VOID
+HalpVideoReboot()
+{
+ if (HalpResetDisplayParameters && !HalpOwnsDisplay) {
+ //
+ // Video work-around. The video driver has a reset function,
+ // call it before resetting the system in case the bios doesn't
+ // know how to reset the displays video mode.
+ //
+
+ if (HalpResetDisplayParameters(COLS, ROWS)) {
+ // display was reset, make sure it's blank
+ HalpClearDisplay();
+ }
+ }
+}
+
+
+
+VOID
+HalpInitializeDisplay(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes the VGA display. This uses HalpMapPhysicalMemory to map
+ the video buffer at 0xb8000 - 0xba000 into high virtual memory.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ if (HalpDisplayInitialized == FALSE) {
+
+ HalpDisplayInitialized = TRUE;
+
+ KeInitializeSpinLock(&HalpDisplayLock);
+
+ //
+ // If somebody called HalDisplayString before Phase 0 initialization,
+ // the video buffer has already been mapped and cleared, and a
+ // message has already been displayed. So we don't want to clear
+ // the screen again, or map the screen again.
+ //
+
+ //
+ // Map two pages of memory starting at physical address 0xb8000.
+ //
+
+ VideoBuffer = (PUSHORT)HalpMapPhysicalMemory((PVOID)0xb8000,2);
+
+ HalpClearDisplay();
+ }
+}
+
+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.
+
+--*/
+
+{
+ if (!HalpDisplayInitialized && HalpOwnsDisplay) {
+
+ //
+ // If somebody has called HalDisplayString before Phase 0
+ // initialization, we need to make sure we get our message out
+ // anyway. So we initialize the display before HalInitSystem does.
+ // HalpInitializeDisplay is smart enough to only map the video
+ // buffer and clear the screen the first time it is called.
+ //
+
+ HalpInitializeDisplay();
+ }
+
+ //
+ // Synchronize access to the display so that MP systems won't
+ // get garbage output due to simultaneous calls. It also prevents
+ // two processors from attempting to call BIOS and reset the display
+ // simultaneously.
+ //
+
+ KiAcquireSpinLock(&HalpDisplayLock);
+
+ if (HalpOwnsDisplay == 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) {
+ HalpOwnsDisplay = HalpResetDisplayParameters(COLS, ROWS);
+ }
+
+ if (HalpOwnsDisplay == FALSE) {
+ HalpBiosDisplayReset();
+ }
+
+ HalpOwnsDisplay = TRUE;
+ HalpDoingCrashDump = TRUE;
+ HalpClearDisplay();
+ }
+
+ while (*String) {
+
+ switch (*String) {
+ case '\n':
+ HalpNextLine();
+ break;
+ case '\r':
+ HalpCursorX = 0;
+ break;
+ default:
+ HalpPutCharacter(*String);
+ if (++HalpCursorX == COLS) {
+ HalpNextLine();
+ }
+ }
+ ++String;
+ }
+
+ KiReleaseSpinLock(&HalpDisplayLock);
+ return;
+}
+
+VOID
+HalpDisplayDebugStatus (
+ PUCHAR str,
+ ULONG len
+ )
+{
+ PUSHORT p;
+
+ if (!HalpDisplayInitialized || !HalpOwnsDisplay) {
+ return;
+ }
+
+ for (p = &VideoBuffer [COLS - len]; len; str++, p++, len--) {
+ *p = (USHORT)((REVERSE_ATTRIBUTE << 8) | *str);
+ }
+}
+
+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.
+
+--*/
+{
+ *WidthInCharacters = COLS;
+ *HeightInLines = ROWS;
+ *CursorColumn = HalpCursorX;
+ *CursorRow = HalpCursorX;
+
+}
+
+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.
+
+--*/
+{
+ HalpCursorX = CursorColumn >= COLS ? COLS-1 : CursorColumn;
+ HalpCursorY = CursorRow >= ROWS ? ROWS-1 : CursorRow;
+}
+
+VOID
+HalpNextLine(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Moves the cursor to the start of the next line, scrolling if necessary.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if (HalpCursorY==ROWS-1) {
+ HalpScrollDisplay();
+ } else {
+ ++HalpCursorY;
+ }
+ HalpCursorX = 0;
+}
+
+VOID
+HalpScrollDisplay(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Scrolls the text on the display up one line.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PUSHORT NewStart;
+ ULONG i;
+
+
+ NewStart = VideoBuffer+COLS;
+ RtlMoveMemory(VideoBuffer, NewStart, (ROWS-1)*COLS*sizeof(USHORT));
+
+ for (i=(ROWS-1)*COLS; i<ROWS*COLS; i++) {
+ VideoBuffer[i] = (REVERSE_ATTRIBUTE << 8) | ' ';
+ }
+}
+
+VOID
+HalpPutCharacter(
+ IN UCHAR Character
+ )
+
+/*++
+
+Routine Description:
+
+ Places a character on the console screen. It uses the variables
+ HalpCursorX and HalpCursorY to determine the character's location.
+
+Arguments:
+
+ Character - Supplies the character to be displayed
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ VideoBuffer[HalpCursorY*COLS + HalpCursorX] =
+ (USHORT)((REVERSE_ATTRIBUTE << 8) | Character);
+}
+
+VOID
+HalpClearDisplay(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Clears the video display and sets the current cursor position to the
+ upper left-hand corner.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ USHORT Attribute;
+ ULONG i;
+
+ Attribute = (REVERSE_ATTRIBUTE << 8) | ' ';
+ for (i=0; i < ROWS*COLS; i++) {
+ VideoBuffer[i] = Attribute;
+ }
+ HalpCursorX=0;
+ HalpCursorY=0;
+
+}
diff --git a/private/ntos/nthals/halx86/i386/xxflshbf.c b/private/ntos/nthals/halx86/i386/xxflshbf.c
new file mode 100644
index 000000000..18a5ff5b4
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/xxflshbf.c
@@ -0,0 +1,52 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ xxflshbf.c
+
+Abstract:
+
+ This module implements i386 machine dependent kernel functions to flush
+ write buffers.
+
+Author:
+
+ David N. Cutler (davec) 26-Apr-1990
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "nthal.h"
+
+VOID
+KeFlushWriteBuffer (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function flushes the write buffer on the current processor.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ return;
+}
diff --git a/private/ntos/nthals/halx86/i386/xxhal.c b/private/ntos/nthals/halx86/i386/xxhal.c
new file mode 100644
index 000000000..ab8595e5d
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/xxhal.c
@@ -0,0 +1,462 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ xxhal.c
+
+Abstract:
+
+
+ This module implements the initialization of the system dependent
+ functions that define the Hardware Architecture Layer (HAL) for an
+ x86 system.
+
+Author:
+
+ David N. Cutler (davec) 25-Apr-1991
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+
+
+ULONG HalpBusType;
+
+extern ADDRESS_USAGE HalpDefaultPcIoSpace;
+extern ADDRESS_USAGE HalpEisaIoSpace;
+extern UCHAR HalpSzPciLock[];
+extern UCHAR HalpSzBreak[];
+extern BOOLEAN HalpPciLockSettings;
+extern UCHAR HalpGenuineIntel[];
+
+VOID
+HalpGetParameters (
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ );
+
+ULONG
+HalpGetFeatureBits (
+ VOID
+ );
+
+#ifndef NT_UP
+ULONG
+HalpInitMP(
+ IN ULONG Phase,
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ );
+#endif
+
+
+extern KSPIN_LOCK Halp8254Lock;
+KSPIN_LOCK HalpSystemHardwareLock;
+
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,HalpGetParameters)
+#pragma alloc_text(INIT,HalInitSystem)
+#pragma alloc_text(INIT,HalpGetFeatureBits)
+#endif
+
+
+VOID
+HalpGetParameters (
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ )
+/*++
+
+Routine Description:
+
+ This gets any parameters from the boot.ini invocation line.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None
+
+--*/
+{
+ PCHAR Options;
+
+ if (LoaderBlock != NULL && LoaderBlock->LoadOptions != NULL) {
+ Options = LoaderBlock->LoadOptions;
+
+ //
+ // Check if PCI settings are locked down
+ //
+
+ if (strstr(Options, HalpSzPciLock)) {
+ HalpPciLockSettings = TRUE;
+ }
+
+ //
+ // Has the user asked for an initial BreakPoint?
+ //
+
+ if (strstr(Options, HalpSzBreak)) {
+ DbgBreakPoint();
+ }
+ }
+
+ return;
+}
+
+
+
+BOOLEAN
+HalInitSystem (
+ IN ULONG Phase,
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ )
+
+
+/*++
+
+Routine Description:
+
+ This function initializes the Hardware Architecture Layer (HAL) for an
+ x86 system.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A value of TRUE is returned is the initialization was successfully
+ complete. Otherwise a value of FALSE is returend.
+
+--*/
+
+{
+ PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
+ PLIST_ENTRY NextMd;
+ KIRQL CurrentIrql;
+ PKPRCB pPRCB;
+
+ pPRCB = KeGetCurrentPrcb();
+
+ if (Phase == 0) {
+
+ HalpBusType = LoaderBlock->u.I386.MachineType & 0x00ff;
+ HalpGetParameters (LoaderBlock);
+
+ //
+ // Verify Prcb version and build flags conform to
+ // this image
+ //
+
+#if DBG
+ if (!(pPRCB->BuildType & PRCB_BUILD_DEBUG)) {
+ // This checked hal requires a checked kernel
+ KeBugCheckEx (MISMATCHED_HAL,
+ 2, pPRCB->BuildType, PRCB_BUILD_DEBUG, 0);
+ }
+#else
+ if (pPRCB->BuildType & PRCB_BUILD_DEBUG) {
+ // This free hal requires a free kernel
+ KeBugCheckEx (MISMATCHED_HAL, 2, pPRCB->BuildType, 0, 0);
+ }
+#endif
+#ifndef NT_UP
+ if (pPRCB->BuildType & PRCB_BUILD_UNIPROCESSOR) {
+ // This MP hal requires an MP kernel
+ KeBugCheckEx (MISMATCHED_HAL, 2, pPRCB->BuildType, 0, 0);
+ }
+#endif
+ if (pPRCB->MajorVersion != PRCB_MAJOR_VERSION) {
+ KeBugCheckEx (MISMATCHED_HAL,
+ 1, pPRCB->MajorVersion, PRCB_MAJOR_VERSION, 0);
+ }
+
+ //
+ // Phase 0 initialization
+ // only called by P0
+ //
+
+ //
+ // Check to make sure the MCA HAL is not running on an ISA/EISA
+ // system, and vice-versa.
+ //
+#if MCA
+ if (HalpBusType != MACHINE_TYPE_MCA) {
+ KeBugCheckEx (MISMATCHED_HAL,
+ 3, HalpBusType, MACHINE_TYPE_MCA, 0);
+ }
+#else
+ if (HalpBusType == MACHINE_TYPE_MCA) {
+ KeBugCheckEx (MISMATCHED_HAL,
+ 3, HalpBusType, 0, 0);
+ }
+#endif
+
+ HalpInitializePICs();
+
+ //
+ // Now that the PICs are initialized, we need to mask them to
+ // reflect the current Irql
+ //
+
+ CurrentIrql = KeGetCurrentIrql();
+ CurrentIrql = KfRaiseIrql(CurrentIrql);
+
+ //
+ // Initialize CMOS
+ //
+
+ HalpInitializeCmos();
+
+ //
+ // Fill in handlers for APIs which this hal supports
+ //
+
+ HalQuerySystemInformation = HaliQuerySystemInformation;
+ HalSetSystemInformation = HaliSetSystemInformation;
+
+ //
+ // Register cascade vector
+ //
+
+ HalpRegisterVector (
+ InternalUsage,
+ PIC_SLAVE_IRQ + PRIMARY_VECTOR_BASE,
+ PIC_SLAVE_IRQ + PRIMARY_VECTOR_BASE,
+ HIGH_LEVEL );
+
+ //
+ // Register base IO space used by hal
+ //
+
+ HalpRegisterAddressUsage (&HalpDefaultPcIoSpace);
+ if (HalpBusType == MACHINE_TYPE_EISA) {
+ HalpRegisterAddressUsage (&HalpEisaIoSpace);
+ }
+
+ //
+ // Note that HalpInitializeClock MUST be called after
+ // HalpInitializeStallExecution, because HalpInitializeStallExecution
+ // reprograms the timer.
+ //
+
+ HalpInitializeStallExecution(0);
+
+ //
+ // Setup the clock
+ //
+
+ HalpInitializeClock();
+
+ //
+ // Make sure profile is disabled
+ //
+
+ HalStopProfileInterrupt(0);
+
+ HalpInitializeDisplay();
+
+ //
+ // Initialize spinlock used by HalGetBusData hardware access routines
+ //
+
+ KeInitializeSpinLock(&HalpSystemHardwareLock);
+
+ //
+ // Determine if there is physical memory above 16 MB.
+ //
+
+ LessThan16Mb = TRUE;
+
+ NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
+
+ while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {
+ Descriptor = CONTAINING_RECORD( NextMd,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry );
+
+ if (Descriptor->MemoryType != LoaderFirmwarePermanent &&
+ Descriptor->MemoryType != LoaderSpecialMemory &&
+ Descriptor->BasePage + Descriptor->PageCount > 0x1000) {
+ LessThan16Mb = FALSE;
+ break;
+ }
+
+ NextMd = Descriptor->ListEntry.Flink;
+ }
+
+ //
+ // Determine the size need for map buffers. If this system has
+ // memory with a physical address of greater than
+ // MAXIMUM_PHYSICAL_ADDRESS, then allocate a large chunk; otherwise,
+ // allocate a small chunk.
+ //
+
+ if (LessThan16Mb) {
+
+ //
+ // Allocate a small set of map buffers. They are only need for
+ // slave DMA devices.
+ //
+
+ HalpMapBufferSize = INITIAL_MAP_BUFFER_SMALL_SIZE;
+
+ } else {
+
+ //
+ // Allocate a larger set of map buffers. These are used for
+ // slave DMA controllers and Isa cards.
+ //
+
+ HalpMapBufferSize = INITIAL_MAP_BUFFER_LARGE_SIZE;
+
+ }
+
+ //
+ // Allocate map buffers for the adapter objects
+ //
+
+ HalpMapBufferPhysicalAddress.LowPart =
+ HalpAllocPhysicalMemory (LoaderBlock, MAXIMUM_PHYSICAL_ADDRESS,
+ HalpMapBufferSize >> PAGE_SHIFT, TRUE);
+ HalpMapBufferPhysicalAddress.HighPart = 0;
+
+
+ if (!HalpMapBufferPhysicalAddress.LowPart) {
+
+ //
+ // There was not a satisfactory block. Clear the allocation.
+ //
+
+ HalpMapBufferSize = 0;
+ }
+
+ } else {
+
+ //
+ // Phase 1 initialization
+ //
+
+ if (pPRCB->Number == 0) {
+
+ //
+ // If P0, then setup global vectors
+ //
+
+ HalpRegisterInternalBusHandlers ();
+
+ //
+ // Set feature bits
+ //
+
+ HalpFeatureBits = HalpGetFeatureBits();
+
+ HalpEnableInterruptHandler (
+ DeviceUsage, // Report as device vector
+ V2I (CLOCK_VECTOR), // Bus interrupt level
+ CLOCK_VECTOR, // System IDT
+ CLOCK2_LEVEL, // System Irql
+ HalpClockInterrupt, // ISR
+ Latched );
+
+ HalpEnableInterruptHandler (
+ DeviceUsage, // Report as device vector
+ V2I (PROFILE_VECTOR), // Bus interrupt level
+ PROFILE_VECTOR, // System IDT
+ PROFILE_LEVEL, // System Irql
+ HalpProfileInterrupt, // ISR
+ Latched );
+
+ //
+ // If 486, the FP error will be routed via trap10. So we
+ // don't enable irq13. Otherwise (CPU=386), we will enable irq13
+ // to handle FP error.
+ //
+
+ if (pPRCB->CpuType == 3) {
+ HalpEnableInterruptHandler (
+ DeviceUsage, // Report as device vector
+ V2I (I386_80387_VECTOR), // Bus interrupt level
+ I386_80387_VECTOR, // System IDT
+ I386_80387_IRQL, // System Irql
+ HalpIrq13Handler, // ISR
+ Latched );
+ }
+ }
+
+ }
+
+
+#ifndef NT_UP
+ HalpInitMP (Phase, LoaderBlock);
+#endif
+
+ return TRUE;
+}
+
+ULONG
+HalpGetFeatureBits (
+ VOID
+ )
+{
+ UCHAR Buffer[50];
+ ULONG Junk, ProcessorFeatures, Bits;
+ PKPRCB Prcb;
+
+ Bits = 0;
+
+ Prcb = KeGetCurrentPrcb();
+
+ if (!Prcb->CpuID) {
+ return Bits;
+ }
+
+ //
+ // Determine the processor type
+ //
+
+ HalpCpuID (0, &Junk, (PULONG) Buffer+0, (PULONG) Buffer+2, (PULONG) Buffer+1);
+ Buffer[12] = 0;
+
+ //
+ // If this is an Intel processor, determine whichNT compatible
+ // features are present
+ //
+
+ if (strcmp (Buffer, HalpGenuineIntel) == 0) {
+
+ HalpCpuID (1, &Junk, &Junk, &Junk, &ProcessorFeatures);
+
+ //
+ // Check Intel feature bits for HAL features needed
+ //
+
+ if (Prcb->CpuType == 6) {
+ Bits |= HAL_PERF_EVENTS;
+ }
+
+ if (Prcb->CpuType < 6) {
+ Bits |= HAL_NO_SPECULATION;
+ }
+
+ if (ProcessorFeatures & CPUID_MCA_MASK) {
+ Bits |= HAL_MCA_PRESENT;
+ }
+
+ if (ProcessorFeatures & CPUID_MCE_MASK) {
+ Bits |= HAL_MCE_PRESENT;
+ }
+
+ }
+
+ return Bits;
+}
diff --git a/private/ntos/nthals/halx86/i386/xxioacc.asm b/private/ntos/nthals/halx86/i386/xxioacc.asm
new file mode 100644
index 000000000..8d53fe90a
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/xxioacc.asm
@@ -0,0 +1,386 @@
+ title "ix ioaccess"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; ixioacc.asm
+;
+; Abstract:
+;
+; Procedures to correctly touch I/O registers.
+;
+; Author:
+;
+; Bryan Willman (bryanwi) 16 May 1990
+;
+; Environment:
+;
+; User or Kernel, although privledge (IOPL) may be required.
+;
+; Revision History:
+;
+;--
+
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+ .list
+
+_TEXT$00 SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+;++
+;
+; I/O port space read and write functions.
+;
+; These have to be actual functions on the 386, because we need
+; to use assembler, but cannot return a value if we inline it.
+;
+; This set of functions manipulates I/O registers in PORT space.
+; (Uses x86 in and out instructions)
+;
+; WARNING: Port addresses must always be in the range 0 to 64K, because
+; that's the range the hardware understands.
+;
+;--
+
+
+
+;++
+;
+; UCHAR
+; READ_PORT_UCHAR(
+; PUCHAR Port
+; )
+;
+; Arguments:
+; (esp+4) = Port
+;
+; Returns:
+; Value in Port.
+;
+;--
+cPublicProc _READ_PORT_UCHAR ,1
+cPublicFpo 1, 0
+
+ xor eax, eax ; Eliminate partial stall on return to caller
+
+ mov edx,[esp+4] ; (dx) = Port
+ in al,dx
+ stdRET _READ_PORT_UCHAR
+
+stdENDP _READ_PORT_UCHAR
+
+
+
+;++
+;
+; USHORT
+; READ_PORT_USHORT(
+; PUSHORT Port
+; )
+;
+; Arguments:
+; (esp+4) = Port
+;
+; Returns:
+; Value in Port.
+;
+;--
+cPublicProc _READ_PORT_USHORT ,1
+cPublicFpo 1, 0
+
+ xor eax, eax ; Eliminate partial stall on return to caller
+
+ mov edx,[esp+4] ; (dx) = Port
+ in ax,dx
+ stdRET _READ_PORT_USHORT
+
+stdENDP _READ_PORT_USHORT
+
+
+
+;++
+;
+; ULONG
+; READ_PORT_ULONG(
+; PULONG Port
+; )
+;
+; Arguments:
+; (esp+4) = Port
+;
+; Returns:
+; Value in Port.
+;
+;--
+cPublicProc _READ_PORT_ULONG ,1
+cPublicFpo 1, 0
+
+ mov edx,[esp+4] ; (dx) = Port
+ in eax,dx
+ stdRET _READ_PORT_ULONG
+
+stdENDP _READ_PORT_ULONG
+
+
+
+;++
+;
+; VOID
+; READ_PORT_BUFFER_UCHAR(
+; PUCHAR Port,
+; PUCHAR Buffer,
+; ULONG Count
+; )
+;
+; Arguments:
+; (esp+4) = Port
+; (esp+8) = Buffer address
+; (esp+12) = Count
+;
+;--
+cPublicProc _READ_PORT_BUFFER_UCHAR ,3
+cPublicFpo 3, 0
+
+ mov eax, edi ; Save edi
+
+ mov edx,[esp+4] ; (dx) = Port
+ mov edi,[esp+8] ; (edi) = buffer
+ mov ecx,[esp+12] ; (ecx) = transfer count
+ rep insb
+ mov edi, eax
+ stdRET _READ_PORT_BUFFER_UCHAR
+
+stdENDP _READ_PORT_BUFFER_UCHAR
+
+
+;++
+;
+; VOID
+; READ_PORT_BUFFER_USHORT(
+; PUSHORT Port,
+; PUSHORT Buffer,
+; ULONG Count
+; )
+;
+; Arguments:
+; (esp+4) = Port
+; (esp+8) = Buffer address
+; (esp+12) = Count
+;
+;--
+cPublicProc _READ_PORT_BUFFER_USHORT ,3
+cPublicFpo 3, 0
+
+ mov eax, edi ; Save edi
+
+ mov edx,[esp+4] ; (dx) = Port
+ mov edi,[esp+8] ; (edi) = buffer
+ mov ecx,[esp+12] ; (ecx) = transfer count
+ rep insw
+ mov edi, eax
+ stdRET _READ_PORT_BUFFER_USHORT
+
+stdENDP _READ_PORT_BUFFER_USHORT
+
+
+;++
+;
+; VOID
+; READ_PORT_BUFFER_ULONG(
+; PULONG Port,
+; PULONG Buffer,
+; ULONG Count
+; )
+;
+; Arguments:
+; (esp+4) = Port
+; (esp+8) = Buffer address
+; (esp+12) = Count
+;
+;--
+cPublicProc _READ_PORT_BUFFER_ULONG ,3
+cPublicFpo 3, 0
+
+ mov eax, edi ; Save edi
+
+ mov edx,[esp+4] ; (dx) = Port
+ mov edi,[esp+8] ; (edi) = buffer
+ mov ecx,[esp+12] ; (ecx) = transfer count
+ rep insd
+ mov edi, eax
+ stdRET _READ_PORT_BUFFER_ULONG
+
+stdENDP _READ_PORT_BUFFER_ULONG
+
+
+
+;++
+;
+; VOID
+; WRITE_PORT_UCHAR(
+; PUCHAR Port,
+; UCHAR Value
+; )
+;
+; Arguments:
+; (esp+4) = Port
+; (esp+8) = Value
+;
+;--
+cPublicProc _WRITE_PORT_UCHAR ,2
+cPublicFpo 2, 0
+
+ mov edx,[esp+4] ; (dx) = Port
+ mov al,[esp+8] ; (al) = Value
+ out dx,al
+ stdRET _WRITE_PORT_UCHAR
+
+stdENDP _WRITE_PORT_UCHAR
+
+
+
+;++
+;
+; VOID
+; WRITE_PORT_USHORT(
+; PUSHORT Port,
+; USHORT Value
+; )
+;
+; Arguments:
+; (esp+4) = Port
+; (esp+8) = Value
+;
+;--
+cPublicProc _WRITE_PORT_USHORT ,2
+cPublicFpo 2, 0
+
+ mov edx,[esp+4] ; (dx) = Port
+ mov eax,[esp+8] ; (ax) = Value
+ out dx,ax
+ stdRET _WRITE_PORT_USHORT
+
+stdENDP _WRITE_PORT_USHORT
+
+
+
+;++
+;
+; VOID
+; WRITE_PORT_ULONG(
+; PULONG Port,
+; ULONG Value
+; )
+;
+; Arguments:
+; (esp+4) = Port
+; (esp+8) = Value
+;
+;--
+cPublicProc _WRITE_PORT_ULONG ,2
+cPublicFpo 2, 0
+
+ mov edx,[esp+4] ; (dx) = Port
+ mov eax,[esp+8] ; (eax) = Value
+ out dx,eax
+ stdRET _WRITE_PORT_ULONG
+
+stdENDP _WRITE_PORT_ULONG
+
+
+
+;++
+;
+; VOID
+; WRITE_PORT_BUFFER_UCHAR(
+; PUCHAR Port,
+; PUCHAR Buffer,
+; ULONG Count
+; )
+;
+; Arguments:
+; (esp+4) = Port
+; (esp+8) = Buffer address
+; (esp+12) = Count
+;
+;--
+cPublicProc _WRITE_PORT_BUFFER_UCHAR ,3
+cPublicFpo 3, 0
+
+ mov eax,esi ; Save esi
+ mov edx,[esp+4] ; (dx) = Port
+ mov esi,[esp+8] ; (esi) = buffer
+ mov ecx,[esp+12] ; (ecx) = transfer count
+ rep outsb
+ mov esi,eax
+ stdRET _WRITE_PORT_BUFFER_UCHAR
+
+stdENDP _WRITE_PORT_BUFFER_UCHAR
+
+
+;++
+;
+; VOID
+; WRITE_PORT_BUFFER_USHORT(
+; PUSHORT Port,
+; PUSHORT Buffer,
+; ULONG Count
+; )
+;
+; Arguments:
+; (esp+4) = Port
+; (esp+8) = Buffer address
+; (esp+12) = Count
+;
+;--
+cPublicProc _WRITE_PORT_BUFFER_USHORT ,3
+cPublicFpo 3, 0
+
+ mov eax,esi ; Save esi
+ mov edx,[esp+4] ; (dx) = Port
+ mov esi,[esp+8] ; (esi) = buffer
+ mov ecx,[esp+12] ; (ecx) = transfer count
+ rep outsw
+ mov esi,eax
+ stdRET _WRITE_PORT_BUFFER_USHORT
+
+stdENDP _WRITE_PORT_BUFFER_USHORT
+
+
+;++
+;
+; VOID
+; WRITE_PORT_BUFFER_ULONG(
+; PULONG Port,
+; PULONG Buffer,
+; ULONG Count
+; )
+;
+; Arguments:
+; (esp+4) = Port
+; (esp+8) = Buffer address
+; (esp+12) = Count
+;
+;--
+cPublicProc _WRITE_PORT_BUFFER_ULONG ,3
+cPublicFpo 3, 0
+
+ mov eax,esi ; Save esi
+ mov edx,[esp+4] ; (dx) = Port
+ mov esi,[esp+8] ; (esi) = buffer
+ mov ecx,[esp+12] ; (ecx) = transfer count
+ rep outsd
+ mov esi,eax
+ stdRET _WRITE_PORT_BUFFER_ULONG
+
+stdENDP _WRITE_PORT_BUFFER_ULONG
+
+
+_TEXT$00 ends
+
+ end
diff --git a/private/ntos/nthals/halx86/i386/xxkdsup.c b/private/ntos/nthals/halx86/i386/xxkdsup.c
new file mode 100644
index 000000000..62ee9da82
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/xxkdsup.c
@@ -0,0 +1,404 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ xxkdsup.c
+
+Abstract:
+
+ Com support. Code to init a com port, store port state, map
+ portable procedures to x86 procedures.
+
+Author:
+
+ Bryan M. Willman (bryanwi) 24-Sep-90
+
+Revision History:
+
+ Shielin Tzong (shielint) 10-Apr-91
+ Add packet control protocol.
+
+ John Vert (jvert) 11-Jul-1991
+ Moved from KD/i386 to HAL
+
+--*/
+
+#include "halp.h"
+#include "ixkdcom.h"
+#include "stdio.h"
+
+//
+// This MUST be initialized to zero so we know not to do anything when
+// CpGetByte is called when the kernel debugger is disabled.
+//
+
+CPPORT Port = {NULL, 0, PORT_DEFAULTRATE };
+
+//
+// Remember the debugger port information
+//
+
+CPPORT PortInformation = {NULL, 0, PORT_DEFAULTRATE};
+ULONG ComPort = 0;
+
+//
+// We need this so the serial driver knows that the kernel debugger
+// is using a particular port. The serial driver then knows not to
+// touch this port. KdInitCom fills this in with the number of the
+// COM port it is using (1 or 2)
+//
+// This will go in the registry as soon as the registry is working.
+//
+PUCHAR KdComPortInUse=NULL;
+
+
+BOOLEAN
+KdPortInitialize(
+ PDEBUG_PARAMETERS DebugParameters,
+ PLOADER_PARAMETER_BLOCK LoaderBlock,
+ BOOLEAN Initialize
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure checks for which COM port should be used by kernel
+ debugger. If DebugParameter specifies a COM port, we will use it
+ even if we can not find it (we trust user). Otherwise, if COM2
+ is present and there is no mouse attaching to it, we use COM2.
+ If COM2 is not availabe, we check COM1. If both COM1 and COM2 are
+ not present, we give up and return false.
+
+Arguments:
+
+ DebugParameters - Supplies a pointer a structure which optionally
+ sepcified the debugging port information.
+
+ 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.
+
+Returned Value:
+
+ TRUE - If a debug port is found.
+
+--*/
+
+{
+
+ PCONFIGURATION_COMPONENT_DATA ConfigurationEntry, ChildEntry;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
+ PCM_PARTIAL_RESOURCE_LIST List;
+ ULONG MatchKey, i;
+ ULONG BaudRate = BD_19200;
+ PUCHAR PortAddress = NULL;
+ ULONG Com = 0;
+ UCHAR DebugMessage[80];
+
+ //
+ // Check if Port and baudrate have been determined.
+ //
+
+ if (PortInformation.Address == NULL) {
+
+ //
+ // First see if the DebugParameters contains debugging port info.
+ //
+
+ if (DebugParameters->BaudRate != 0) {
+ BaudRate = DebugParameters->BaudRate;
+ Port.Flags &= ~PORT_DEFAULTRATE;
+ }
+
+ if (DebugParameters->CommunicationPort != 0) {
+
+ //
+ // Find the configuration information of the specified serial port.
+ //
+
+ Com = DebugParameters->CommunicationPort;
+ MatchKey = Com - 1;
+ if (LoaderBlock != NULL) {
+ ConfigurationEntry = KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot,
+ ControllerClass,
+ SerialController,
+ &MatchKey);
+
+ } else {
+ ConfigurationEntry = NULL;
+ }
+
+ } else {
+
+ //
+ // Check if COM2 is present and make sure no mouse attaches to it.
+ //
+
+ MatchKey = 1;
+ if (LoaderBlock != NULL) {
+ ConfigurationEntry = KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot,
+ ControllerClass,
+ SerialController,
+ &MatchKey);
+
+ } else {
+ ConfigurationEntry = NULL;
+ }
+
+ if (ConfigurationEntry != NULL) {
+ ChildEntry = ConfigurationEntry->Child;
+ if ((ChildEntry != NULL) &&
+ (ChildEntry->ComponentEntry.Type == PointerPeripheral)) {
+ ConfigurationEntry = NULL;
+ }
+ }
+
+ //
+ // If COM2 does not exist or a serial mouse attaches to it, try
+ // COM1. If COM1 exists, we will use it no matter what is on
+ // it.
+ //
+
+ if (ConfigurationEntry == NULL) {
+ MatchKey = 0;
+ if (LoaderBlock != NULL) {
+ ConfigurationEntry = KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot,
+ ControllerClass,
+ SerialController,
+ &MatchKey);
+
+ } else {
+ ConfigurationEntry = NULL;
+ }
+
+ if (ConfigurationEntry != NULL) {
+ Com = 1;
+ } else if (CpDoesPortExist((PUCHAR)COM2_PORT)) {
+ PortAddress = (PUCHAR)COM2_PORT;
+ Com = 2;
+ } else if (CpDoesPortExist((PUCHAR)COM1_PORT)) {
+ PortAddress = (PUCHAR)COM1_PORT;
+ Com = 1;
+ } else {
+ return(FALSE);
+ }
+ } else {
+ Com = 2;
+ }
+ }
+
+ //
+ // Get Comport address from the component configuration data.
+ // (If we find the ComponentEntry associated with the com port)
+ //
+
+ if (ConfigurationEntry) {
+ List = (PCM_PARTIAL_RESOURCE_LIST)ConfigurationEntry->ConfigurationData;
+ for (i = 0; i < List->Count ; i++ ) {
+ Descriptor = &List->PartialDescriptors[i];
+ if (Descriptor->Type == CmResourceTypePort) {
+ PortAddress = (PUCHAR)Descriptor->u.Port.Start.LowPart;
+ }
+ }
+ }
+
+ //
+ // If we can not find the port address for the comport, simply use
+ // default value.
+ //
+
+ if (PortAddress == NULL) {
+ switch (Com) {
+ case 1:
+ PortAddress = (PUCHAR)0x3f8;
+ break;
+ case 2:
+ PortAddress = (PUCHAR)0x2f8;
+ break;
+ case 3:
+ PortAddress = (PUCHAR)0x3e8;
+ break;
+ case 4:
+ PortAddress = (PUCHAR)0x2e8;
+ }
+ }
+
+ //
+ // Initialize the port structure.
+ //
+
+ ComPort = Com;
+ PortInformation.Address = PortAddress;
+ PortInformation.Baud = BaudRate;
+ }
+
+ if (Initialize == TRUE) {
+ CpInitialize(&Port,
+ PortInformation.Address,
+ PortInformation.Baud
+ );
+ KdComPortInUse= PortInformation.Address;
+ sprintf(DebugMessage, MSG_DEBUG_ENABLE,
+ ComPort, PortInformation.Address, PortInformation.Baud);
+ HalDisplayString("\n");
+ HalDisplayString(DebugMessage);
+ }
+ return(TRUE);
+}
+
+ULONG
+KdPortGetByte (
+ OUT PUCHAR Input
+ )
+
+/*++
+
+Routine Description:
+
+ Fetch a byte from the debug port and return it.
+
+ 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 - Returns the data byte.
+
+Return Value:
+
+ CP_GET_SUCCESS is returned if a byte is successfully read from the
+ kernel debugger line.
+ CP_GET_ERROR is returned if error encountered during reading.
+ CP_GET_NODATA is returned if timeout.
+
+--*/
+
+{
+ return CpGetByte(&Port, Input, TRUE);
+}
+
+ULONG
+KdPortPollByte (
+ OUT PUCHAR Input
+ )
+
+/*++
+
+Routine Description:
+
+ Fetch a byte from the debug port and return it if one 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 - Returns the data byte.
+
+Return Value:
+
+ CP_GET_SUCCESS is returned if a byte is successfully read from the
+ kernel debugger line.
+ CP_GET_ERROR is returned if error encountered during reading.
+ CP_GET_NODATA is returned if timeout.
+
+--*/
+
+{
+ return CpGetByte(&Port, Input, FALSE);
+}
+
+VOID
+KdPortPutByte (
+ IN UCHAR Output
+ )
+
+/*++
+
+Routine Description:
+
+ Write a byte to the debug port.
+
+ 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.
+
+--*/
+
+{
+ CpPutByte(&Port, Output);
+}
+
+VOID
+KdPortRestore (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does NOTHING on the x86.
+
+ 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:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ Port.Flags &= ~PORT_SAVED;
+}
+
+VOID
+KdPortSave (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does NOTHING on the x86.
+
+ 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:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ Port.Flags |= PORT_SAVED;
+}
+
diff --git a/private/ntos/nthals/halx86/i386/xxmemory.c b/private/ntos/nthals/halx86/i386/xxmemory.c
new file mode 100644
index 000000000..c88792a85
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/xxmemory.c
@@ -0,0 +1,368 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ xxmemory.c
+
+Abstract:
+
+ Provides routines to allow the HAL to map physical memory.
+
+Author:
+
+ John Vert (jvert) 3-Sep-1991
+
+Environment:
+
+ Phase 0 initialization only.
+
+Revision History:
+
+--*/
+#include "halp.h"
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,HalpAllocPhysicalMemory)
+#endif
+
+
+MEMORY_ALLOCATION_DESCRIPTOR HalpExtraAllocationDescriptor;
+
+//
+// Almost all of the last 4Mb of memory are available to the HAL to map
+// physical memory. The kernel may use a couple of PTEs in this area for
+// special purposes, so skip any which are not zero.
+//
+// Note that the HAL's heap only uses the last 3Mb. This is so we can
+// reserve the first 1Mb for use if we have to return to real mode.
+// In order to return to real mode we need to identity-map the first 1Mb of
+// physical memory.
+//
+PVOID HalpHeapStart=(PVOID)0xffd00000;
+
+
+PVOID
+HalpMapPhysicalMemory(
+ IN PVOID PhysicalAddress,
+ IN ULONG NumberPages
+ )
+
+/*++
+
+Routine Description:
+
+ This routine maps physical memory into the area of virtual memory
+ reserved for the HAL. It does this by directly inserting the PTE
+ into the Page Table which the OS Loader has provided.
+
+ N.B. This routine does *NOT* update the MemoryDescriptorList. The
+ caller is responsible for either removing the appropriate
+ physical memory from the list, or creating a new descriptor to
+ describe it.
+
+Arguments:
+
+ PhysicalAddress - Supplies the physical address of the start of the
+ area of physical memory to be mapped.
+
+ NumberPages - Supplies the number of pages contained in the area of
+ physical memory to be mapped.
+
+Return Value:
+
+ PVOID - Virtual address at which the requested block of physical memory
+ was mapped
+
+ NULL - The requested block of physical memory could not be mapped.
+
+--*/
+
+{
+ PHARDWARE_PTE PTE;
+ ULONG PagesMapped;
+ PVOID VirtualAddress;
+
+ //
+ // The OS Loader sets up hyperspace for us, so we know that the Page
+ // Tables are magically mapped starting at V.A. 0xC0000000.
+ //
+
+ PagesMapped = 0;
+ while (PagesMapped < NumberPages) {
+ //
+ // Look for enough consecutive free ptes to honor mapping
+ //
+
+ PagesMapped = 0;
+ VirtualAddress = HalpHeapStart;
+
+ while (PagesMapped < NumberPages) {
+ PTE=MiGetPteAddress(VirtualAddress);
+ if (*(PULONG)PTE != 0) {
+
+ //
+ // Pte is not free, skip up to the next pte and start over
+ //
+
+ HalpHeapStart = (PVOID) ((ULONG)VirtualAddress + PAGE_SIZE);
+ break;
+ }
+ VirtualAddress = (PVOID) ((ULONG)VirtualAddress + PAGE_SIZE);
+ PagesMapped++;
+ }
+
+ }
+
+
+ PagesMapped = 0;
+ VirtualAddress = (PVOID) ((ULONG) HalpHeapStart | BYTE_OFFSET (PhysicalAddress));
+ while (PagesMapped < NumberPages) {
+ PTE=MiGetPteAddress(HalpHeapStart);
+
+ PTE->PageFrameNumber = ((ULONG)PhysicalAddress >> PAGE_SHIFT);
+ PTE->Valid = 1;
+ PTE->Write = 1;
+
+ PhysicalAddress = (PVOID)((ULONG)PhysicalAddress + PAGE_SIZE);
+ HalpHeapStart = (PVOID)((ULONG)HalpHeapStart + PAGE_SIZE);
+
+ ++PagesMapped;
+ }
+
+ //
+ // Flush TLB
+ //
+ HalpFlushTLB ();
+ return(VirtualAddress);
+}
+
+PVOID
+HalpMapPhysicalMemoryWriteThrough(
+ IN PVOID PhysicalAddress,
+ IN ULONG NumberPages
+)
+/*++
+
+Routine Description:
+
+ Maps a physical memory address into virtual space, same as
+ HalpMapPhysicalMemory(). The difference is that this routine
+ marks the pages as PCD/PWT so that writes to the memory mapped registers
+ mapped here won't get delayed in the future x86 internal write-back caches.
+
+Arguments:
+
+ PhysicalAddress - Supplies a physical address of the memory to be mapped
+
+ NumberPages - Number of pages to map
+
+Return Value:
+
+ Virtual address pointer to the requested physical address
+
+--*/
+{
+ ULONG Index;
+ PHARDWARE_PTE PTE;
+ PVOID VirtualAddress;
+
+ VirtualAddress = HalpMapPhysicalMemory(PhysicalAddress, NumberPages);
+ PTE = MiGetPteAddress(VirtualAddress);
+
+ for (Index = 0; Index < NumberPages; Index++, PTE++) {
+
+ PTE->CacheDisable = 1;
+ PTE->WriteThrough = 1;
+ }
+
+ return VirtualAddress;
+}
+
+
+PVOID
+HalpRemapVirtualAddress(
+ IN PVOID VirtualAddress,
+ IN PVOID PhysicalAddress,
+ IN BOOLEAN WriteThrough
+ )
+/*++
+
+Routine Description:
+
+ This routine remaps a PTE to the physical memory address provided.
+
+Arguments:
+
+ PhysicalAddress - Supplies the physical address of the area to be mapped
+
+ VirtualAddress - Valid address to be remapped
+
+ WriteThrough - Map as cachable or WriteThrough
+
+Return Value:
+
+ PVOID - Virtual address at which the requested block of physical memory
+ was mapped
+
+ NULL - The requested block of physical memory could not be mapped.
+
+--*/
+{
+ PHARDWARE_PTE PTE;
+
+ PTE = MiGetPteAddress (VirtualAddress);
+ PTE->PageFrameNumber = ((ULONG)PhysicalAddress >> PAGE_SHIFT);
+ PTE->Valid = 1;
+ PTE->Write = 1;
+
+ if (WriteThrough) {
+ PTE->CacheDisable = 1;
+ PTE->WriteThrough = 1;
+ }
+
+ //
+ // Flush TLB
+ //
+ HalpFlushTLB();
+ return(VirtualAddress);
+
+}
+
+ULONG
+HalpAllocPhysicalMemory(
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock,
+ IN ULONG MaxPhysicalAddress,
+ IN ULONG NoPages,
+ IN BOOLEAN bAlignOn64k
+ )
+/*++
+
+Routine Description:
+
+ Carves out N pages of physical memory from the memory descriptor
+ list in the desired location. This function is to be called only
+ during phase zero initialization. (ie, before the kernel's memory
+ management system is running)
+
+Arguments:
+
+ MaxPhysicalAddress - The max address where the physical memory can be
+ NoPages - Number of pages to allocate
+
+Return Value:
+
+ The physical address or NULL if the memory could not be obtained.
+
+--*/
+{
+ PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
+ PLIST_ENTRY NextMd;
+ ULONG AlignmentOffset;
+ ULONG MaxPageAddress;
+ ULONG PhysicalAddress;
+
+ MaxPageAddress = MaxPhysicalAddress >> PAGE_SHIFT;
+
+ //
+ // Scan the memory allocation descriptors and allocate map buffers
+ //
+
+ NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
+ while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {
+ Descriptor = CONTAINING_RECORD(NextMd,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+
+ AlignmentOffset = bAlignOn64k ?
+ ((Descriptor->BasePage + 0x0f) & ~0x0f) - Descriptor->BasePage :
+ 0;
+
+ //
+ // Search for a block of memory which is contains a memory chuck
+ // that is greater than size pages, and has a physical address less
+ // than MAXIMUM_PHYSICAL_ADDRESS.
+ //
+
+ if ((Descriptor->MemoryType == LoaderFree ||
+ Descriptor->MemoryType == MemoryFirmwareTemporary) &&
+ (Descriptor->BasePage) &&
+ (Descriptor->PageCount >= NoPages + AlignmentOffset) &&
+ (Descriptor->BasePage + NoPages + AlignmentOffset < MaxPageAddress)) {
+
+ PhysicalAddress =
+ (Descriptor->BasePage + AlignmentOffset) << PAGE_SHIFT;
+ break;
+ }
+
+ NextMd = NextMd->Flink;
+ }
+
+ //
+ // Use the extra descriptor to define the memory at the end of the
+ // original block.
+ //
+
+
+ ASSERT(NextMd != &LoaderBlock->MemoryDescriptorListHead);
+
+ if (NextMd == &LoaderBlock->MemoryDescriptorListHead)
+ return (ULONG)NULL;
+
+ //
+ // Adjust the memory descriptors.
+ //
+
+ if (AlignmentOffset == 0) {
+
+ Descriptor->BasePage += NoPages;
+ Descriptor->PageCount -= NoPages;
+
+ if (Descriptor->PageCount == 0) {
+
+ //
+ // The whole block was allocated,
+ // Remove the entry from the list completely.
+ //
+
+ RemoveEntryList(&Descriptor->ListEntry);
+
+ }
+
+ } else {
+
+ if (Descriptor->PageCount - NoPages - AlignmentOffset) {
+
+ //
+ // Currently we only allow one Align64K allocation
+ //
+ ASSERT (HalpExtraAllocationDescriptor.PageCount == 0);
+
+ //
+ // The extra descriptor is needed so intialize it and insert
+ // it in the list.
+ //
+ HalpExtraAllocationDescriptor.PageCount =
+ Descriptor->PageCount - NoPages - AlignmentOffset;
+
+ HalpExtraAllocationDescriptor.BasePage =
+ Descriptor->BasePage + NoPages + AlignmentOffset;
+
+ HalpExtraAllocationDescriptor.MemoryType = MemoryFree;
+ InsertTailList(
+ &Descriptor->ListEntry,
+ &HalpExtraAllocationDescriptor.ListEntry
+ );
+ }
+
+
+ //
+ // Use the current entry as the descriptor for the first block.
+ //
+
+ Descriptor->PageCount = AlignmentOffset;
+ }
+
+ return PhysicalAddress;
+}
diff --git a/private/ntos/nthals/halx86/i386/xxstubs.c b/private/ntos/nthals/halx86/i386/xxstubs.c
new file mode 100644
index 000000000..251bce23c
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/xxstubs.c
@@ -0,0 +1,131 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ stubs.c
+
+Abstract:
+
+ This implements the HAL routines which don't do anything on x86.
+
+Author:
+
+ John Vert (jvert) 11-Jul-1991
+
+Revision History:
+
+--*/
+#include "nthal.h"
+#include "arc.h"
+#include "arccodes.h"
+
+VOID
+HalSaveState(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Saves the system state into the restart block. Currently does nothing.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Does not return
+
+--*/
+
+{
+ DbgPrint("HalSaveState called - System stopped\n");
+
+ KeBugCheck(0);
+}
+
+
+BOOLEAN
+HalDataBusError(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Called when a data bus error occurs. There is no way to fix this on
+ x86.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ FALSE
+
+--*/
+
+{
+ return(FALSE);
+
+}
+
+BOOLEAN
+HalInstructionBusError(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Called when an instruction bus error occurs. There is no way to fix this
+ on x86.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ FALSE
+
+--*/
+
+{
+ return(FALSE);
+
+}
+
+VOID
+KeFlushWriteBuffer(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Flushes all write buffers and/or other data storing or reordering
+ hardware on the current processor. This ensures that all previous
+ writes will occur before any new reads or writes are completed.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+}
diff --git a/private/ntos/nthals/halx86/i386/xxtime.c b/private/ntos/nthals/halx86/i386/xxtime.c
new file mode 100644
index 000000000..f726cc184
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/xxtime.c
@@ -0,0 +1,91 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ xxtime.c
+
+Abstract:
+
+ This module implements the HAL set/query realtime clock routines for
+ an x86 system.
+
+Author:
+
+ David N. Cutler (davec) 5-May-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+
+BOOLEAN
+HalQueryRealTimeClock (
+ OUT PTIME_FIELDS TimeFields
+ )
+
+/*++
+
+Routine Description:
+
+ This routine queries the realtime clock.
+
+ N.B. This routine assumes that the caller has provided any required
+ synchronization to query the realtime clock information.
+
+Arguments:
+
+ TimeFields - Supplies a pointer to a time structure that receives
+ the realtime clock information.
+
+Return Value:
+
+ If the power to the realtime clock has not failed, then the time
+ values are read from the realtime clock and a value of TRUE is
+ returned. Otherwise, a value of FALSE is returned.
+
+--*/
+
+{
+
+ HalpReadCmosTime(TimeFields);
+ return TRUE;
+}
+
+BOOLEAN
+HalSetRealTimeClock (
+ IN PTIME_FIELDS TimeFields
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the realtime clock.
+
+ N.B. This routine assumes that the caller has provided any required
+ synchronization 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.
+
+--*/
+
+{
+ HalpWriteCmosTime(TimeFields);
+ return TRUE;
+}