295 lines
6.8 KiB
C
295 lines
6.8 KiB
C
|
|
/*++
|
|
|
|
Copyright (c) 1999-2001 Microsoft Corporation. All Rights Reserved.
|
|
|
|
|
|
Module Name:
|
|
|
|
rtp.h
|
|
|
|
Abstract:
|
|
|
|
This header contains private internal realtime executive information.
|
|
|
|
Author:
|
|
|
|
Joseph Ballantyne
|
|
|
|
Environment:
|
|
|
|
Kernel Mode
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
|
|
|
|
#define INSTRUCTIONCOUNT PERFORMANCECOUNTER1
|
|
#define CYCLECOUNT PERFORMANCECOUNTER0
|
|
|
|
|
|
//#define USERING1
|
|
|
|
//#define NONMI 1
|
|
|
|
// When USERING1 is defined, the realtime executive runs realtime threads with
|
|
// a priviledge level of ring 1 rather than ring 0. This allows the executive to
|
|
// trap when code in a realtime thread uses CLI/STI instructions. That allows the
|
|
// realtime executive to syncronize that code with Windows code.
|
|
|
|
|
|
// The real time executive stores eax on the
|
|
// stack and then uses that space in eax to switch to a known valid
|
|
// data segment.
|
|
|
|
// Currently we ALWAYS use a maskable interrupt to take control from Windows.
|
|
|
|
// We use a maskable interrupt to be nice to the OS and also to make
|
|
// sure old debuggers like WDEB work properly.
|
|
|
|
// The real time executive currently always runs the real time threads
|
|
// with interrupts disabled, and uses a NMI interrupt to switch between
|
|
// them.
|
|
|
|
// We always use a private IDT for
|
|
// the realtime executive and the realtime threads. We use them to catch
|
|
// any faults, or exceptions before they get to the normal Windows
|
|
// handlers. It is an error to generate any faults or exceptions inside
|
|
// a real time thread.
|
|
|
|
// Although we used to use the performance counters to generate both the maskable
|
|
// and the non maskable interrupts, and we switched the perf counter
|
|
// interrupt dynamically between generating an NMI, and generating a
|
|
// maskable interrupt, we currently only use the local apic timer interrupt
|
|
// to generate the maskable interrupt. We use the performance counters
|
|
// to generate the NMI to switch between the real time threads.
|
|
|
|
// This eliminates dual sources of maskable interrupts which was causing a
|
|
// single rt thread to get more time than it should have.
|
|
|
|
// One problem with using the performance counters to generate the maskable
|
|
// interrupt was also that the maskable interrupt was not guaranteed to hit -
|
|
// especially when vpowerd is doing idle detection and halting the cpu to
|
|
// reduce power consumption. Unfortunately, I have not yet found a performance
|
|
// counter that will count cycles or bus cycles regardless of the power state
|
|
// of the processor. Not even simply when the processor is halted or in a light
|
|
// power down state.
|
|
|
|
|
|
//#define MASKABLEINTERRUPT 1
|
|
|
|
// If MASKABLEINTERRUPT is defined, then we make the performance counters generate
|
|
// a maskable interrupt! We do this so that we can quickly and surely guarantee
|
|
// that all of the ntkern functions that are called by ks2 are realtime safe.
|
|
// I will go fix those anyway, but to get ks2 up and running quickly, safely,
|
|
// and stable, changing rt.sys to never use NMI is the easiest way to go.
|
|
|
|
|
|
|
|
#define NMIIDTINDEX 2
|
|
#define MASKABLEIDTINDEX 0x4c
|
|
#define APICERRORIDTINDEX 0x4e
|
|
#define APICSPURIOUSIDTINDEX 0x4f // This ABSOLUTELY MUST end in 0xf. Hardware forces that.
|
|
#ifdef MASKABLEINTERRUPT
|
|
#define RTMASKABLEIDTINDEX 0x20
|
|
#define RTINTERRUPT (RTMASKABLEIDTINDEX)
|
|
#else
|
|
#define RTINTERRUPT (NMI|MASKABLEIDTINDEX)
|
|
#endif
|
|
|
|
#define TRANSFERCONTROLIDTINDEX MASKABLEIDTINDEX
|
|
|
|
|
|
// EIPRETURNADDRESSOFFSET is the offset in DWORDS from the bottom of the
|
|
// realtime thread's stack to the EIP DWORD of the IRET return address.
|
|
|
|
#define EIPRETURNADDRESSOFFSET (1)
|
|
|
|
|
|
// CSRETURNADDRESSOFFSET is the offset in DWORDS from the bottom of the
|
|
// realtime thread's stack to the CS DWORD of the IRET return address.
|
|
|
|
#define CSRETURNADDRESSOFFSET (2)
|
|
|
|
|
|
// EFLAGSOFFSET is the offset in DWORDS from the bottom of the
|
|
// realtime thread's stack to the EFLAGS DWORD.
|
|
|
|
#define EFLAGSOFFSET (3)
|
|
|
|
|
|
// RTPTRANSFERCONTROLEFLAGSOFFSET is the offset in DWORDS from the bottom of the
|
|
// realtime thread's stack to the EFLAGS DWORD that is pushed in the
|
|
// RtpTransferControl routine before doing a CLI and eventually transfering control
|
|
// to the realtime executive.
|
|
|
|
#define RTPTRANSFERCONTROLEFLAGSOFFSET (1+EFLAGSOFFSET)
|
|
|
|
|
|
// IF is the bit in the eflags register that is set and cleared to enable
|
|
// and disable maskable interrupts.
|
|
|
|
#define IF 0x200
|
|
|
|
|
|
// This is the starting address of the WDM driver address space on Win9x. All
|
|
// preemtible WDM drivers are loaded into memory with virtual memory addresses
|
|
// equal to or larger than this address.
|
|
|
|
// We use this to check on Win9x if we are being called from a WDM driver or a
|
|
// VXD. We do not support calling realtime functions from VXDs - so we check
|
|
// where we are called from and fail the call if it is not from WDM address
|
|
// space.
|
|
|
|
// On Windows NT, we allow any drivers to call our functions and so do not
|
|
// make this check. It would not work anyway, since the driver address space
|
|
// does not start in the same place anyway.
|
|
|
|
#ifndef UNDER_NT
|
|
#define WDMADDRESSSPACE 0xff000000
|
|
#endif
|
|
|
|
|
|
#define RT_LOG_ENTRY_SIZE 16
|
|
|
|
|
|
|
|
|
|
// This structure is the header to the realtime log.
|
|
|
|
typedef struct {
|
|
PCHAR Buffer;
|
|
ULONG BufferSize;
|
|
ULONG WriteLocation;
|
|
} RTLOGHEADER, *PRTLOGHEADER;
|
|
|
|
|
|
|
|
|
|
extern PRTLOGHEADER RtLog;
|
|
|
|
|
|
// RtExecCS is the real time executive code segment.
|
|
|
|
extern WORD RtExecCS;
|
|
extern WORD RealTimeDS;
|
|
extern WORD RealTimeSS;
|
|
extern WORD RtExecTSS;
|
|
|
|
|
|
// These are globals with information about the processor we are running on.
|
|
|
|
extern ULONG CPUArchitecture;
|
|
extern ULONG CPUManufacturer;
|
|
extern LONG CPUFamily;
|
|
extern LONG CPUModel;
|
|
extern LONG CPUStepping;
|
|
extern ULONGLONG CPUFeatures;
|
|
|
|
|
|
// This global counts the number of times we have switched realtime threads since
|
|
// the machine was booted. Note that this value is not cleared to zero if the
|
|
// machine is hibernated.
|
|
|
|
extern ULONGLONG threadswitchcount;
|
|
|
|
|
|
// This global points to the system irql level.
|
|
|
|
extern PKIRQL pCurrentIrql;
|
|
|
|
|
|
|
|
|
|
// Various prototypes of internally used functions.
|
|
|
|
|
|
BOOL
|
|
SetupRealTimeThreads (
|
|
VOID
|
|
);
|
|
|
|
|
|
VOID
|
|
SetTimeLimit (
|
|
LONG cycles,
|
|
LONG instructions
|
|
);
|
|
|
|
|
|
__inline
|
|
ULONG
|
|
RtpCompareExchange (
|
|
ULONG *destination,
|
|
ULONG source,
|
|
ULONG value
|
|
);
|
|
|
|
|
|
ULONGLONG
|
|
__cdecl
|
|
RtCompareExchange8 (
|
|
ULONGLONG *destination,
|
|
ULONGLONG source,
|
|
ULONGLONG value
|
|
);
|
|
|
|
|
|
NTSTATUS
|
|
RtpCalibrateCpuClock (
|
|
ULONG *cyclesperusec
|
|
);
|
|
|
|
|
|
BOOL
|
|
RtpTransferControl (
|
|
WORD State,
|
|
ULONG Data,
|
|
BOOL (*DoTransfer)(PVOID),
|
|
PVOID Context
|
|
);
|
|
|
|
|
|
VOID
|
|
RtpForceAtomic (
|
|
VOID (*AtomicOperation)(PVOID),
|
|
PVOID Context
|
|
);
|
|
|
|
|
|
VOID
|
|
FASTCALL
|
|
RtKfAcquireLock (
|
|
IN PKSPIN_LOCK SpinLock
|
|
);
|
|
|
|
|
|
VOID
|
|
FASTCALL
|
|
RtKfReleaseLock (
|
|
IN PKSPIN_LOCK SpinLock
|
|
);
|
|
|
|
|
|
KIRQL
|
|
FASTCALL
|
|
RtKfAcquireSpinLock (
|
|
IN PKSPIN_LOCK SpinLock
|
|
);
|
|
|
|
|
|
VOID
|
|
FASTCALL
|
|
RtKfReleaseSpinLock (
|
|
IN PKSPIN_LOCK SpinLock,
|
|
IN KIRQL NewIrql
|
|
);
|
|
|
|
|
|
#define RtpSimulateRtInterrupt() \
|
|
__asm int TRANSFERCONTROLIDTINDEX
|
|
|