Click here to Skip to main content
15,891,316 members
Articles / Programming Languages / C

Access Physical Memory, Port and PCI Configuration Space

Rate me:
Please Sign up or sign in to vote.
4.95/5 (34 votes)
13 Apr 2009CPOL4 min read 227.5K   6.8K   98  
Play with physical memory, port, PCI configuration space in user mode
//////////////////////////////////////////////////////////////////////////////
//	Copyright � 1998,1999 PHD Computer Consultants Ltd
//
//	DebugPrint code to add to a test driver		http://www.phdcc.com/debugprint/
/////////////////////////////////////////////////////////////////////////////
//	DebugPrint.cpp:			Debug printing in test driver
/////////////////////////////////////////////////////////////////////////////
//	DebugPrintInit			Initialise DebugPrint
//	DebugPrintMsg			Print ANSI string
//	DebugPrintClose			Close DebugPrint
//	DebugPrint				Formatted print, allocating 100 byte print buffer
//	DebugPrint2				Formatted print, specifying print buffer size
//*	DebugPrintVA			Allocate DebugPrint buffer and call DebugSprintf
//*	PrintXxx				Print various types to buffer
//*	DebugSprintf			Do formatted print to buffer
//*	ANSIstrlen				Get ANSI string length
//*	DebugPrintSystemThread	System thread to print device events.
//*	OpenDebugPrintDriver	Attempt to open DebugPrt driver for 5 mins
//*	ClearEvents				Clear any remaining events
/////////////////////////////////////////////////////////////////////////////
//	DebugPrinting occurs automatically in checked build
//	To force debug printing in free build, #define DEBUGPRINT 1
/////////////////////////////////////////////////////////////////////////////
//	Format specification characters
//		%c	ANSI char
//		%C	Wide char
//		%d	Signed int in decimal
//		%D	__int64 in decimal
//		%i	Signed int in decimal
//		%I	IRP
//		%l	__int64 in hex
//		%L	LARGE_INTEGER in hex
//		%s	null-terminated ANSI char string
//		%S	null-terminated Wide char string
//		%T	PUNICODE_STRING
//		%u	ULONG in decimal
//		%x	ULONG in hex
//
//	Be very careful to provide appropriate parameters for the formatted string
//	in your calls to DebugPrint.
/////////////////////////////////////////////////////////////////////////////
//	Version history
//	7-Dec-98	1.0.0	CC	creation
//	17-Dec-98	1.0.1	CC	DriverName allocated from NonPagedPool
//	21-Dec-98	1.0.1	CC	sizeof char * used properly
//	28-Dec-98	1.0.2	CC	%* allowed for %sSx
//	22-Jan-99	1.0.3	CC	%D, %l, %L added.  width>'9' allowed
//	16-Feb-99	1.0.4	CC	RtlInitUnicodeString used
//	31-Mar-99	1.0.5	CC	Altered to make it work in NT4
//	24-Apr-99	1.0.5	CC	DebugPrintClose checks DebugPrintStarted
//	25-Apr-99	1.0.5	CC	System thread tries for 5 mins to open DebugPrt
//	13-May-99	1.0.6	CC	IRP_MN_QUERY_LEGACY_BUS_INFORMATION added
//	19-May-99	1.0.6	CC	ThreadExiting ensures that thread finished before unload
/////////////////////////////////////////////////////////////////////////////

#ifdef __cplusplus
extern "C"
{
#endif
#include <wdm.h>
#ifdef __cplusplus
}
#endif

#include "debugprint.h"
#include <stdarg.h>	// OK to use this for va_* macros

#if DODEBUGPRINT

//////////////////////////////////////////////////////////////////////////////
//	Definitions copied from Wdm.h to make this compile in NT4
//	Cross-fingers - lets hope these definitions do not change

#define Dbp_IRP_MJ_POWER                    0x16
#define Dbp_IRP_MJ_SYSTEM_CONTROL           0x17
#define Dbp_IRP_MJ_PNP                      0x1b

#define Dbp_IRP_MN_QUERY_DEVICE_RELATIONS       0x07

#define Dbp_IRP_MN_SET_POWER                    0x02
#define Dbp_IRP_MN_QUERY_POWER                  0x03

typedef enum Dbp__DEVICE_RELATION_TYPE {
    Dbp_BusRelations,
    Dbp_EjectionRelations,
    Dbp_PowerRelations,
    Dbp_RemovalRelations,
    Dbp_TargetDeviceRelation
} Dbp_DEVICE_RELATION_TYPE, *Dbp_PDEVICE_RELATION_TYPE;

typedef struct _Dbp_QueryDeviceRelations
{
	Dbp_DEVICE_RELATION_TYPE Type;
} Dbp_QueryDeviceRelations, *Dbp_PQueryDeviceRelations;

typedef enum _Dbp_SYSTEM_POWER_STATE {
    Dbp_PowerSystemUnspecified = 0,
    Dbp_PowerSystemWorking,
    Dbp_PowerSystemSleeping1,
    Dbp_PowerSystemSleeping2,
    Dbp_PowerSystemSleeping3,
    Dbp_PowerSystemHibernate,
    Dbp_PowerSystemShutdown,
    Dbp_PowerSystemMaximum
} Dbp_SYSTEM_POWER_STATE, *Dbp_PSYSTEM_POWER_STATE;

typedef enum {
    Dbp_PowerActionNone,
    Dbp_PowerActionReserved,
    Dbp_PowerActionSleep,
    Dbp_PowerActionHibernate,
    Dbp_PowerActionShutdown,
    Dbp_PowerActionShutdownReset,
    Dbp_PowerActionShutdownOff
} Dbp_POWER_ACTION, *Dbp_PPOWER_ACTION;

typedef enum _Dbp_DEVICE_POWER_STATE {
    Dbp_PowerDeviceUnspecified = 0,
    Dbp_PowerDeviceD0,
    Dbp_PowerDeviceD1,
    Dbp_PowerDeviceD2,
    Dbp_PowerDeviceD3,
    Dbp_PowerDeviceMaximum
} Dbp_DEVICE_POWER_STATE, *Dbp_PDEVICE_POWER_STATE;

typedef enum _Dbp_POWER_STATE_TYPE {
    Dbp_SystemPowerState,
    Dbp_DevicePowerState
} Dbp_POWER_STATE_TYPE, *Dbp_PPOWER_STATE_TYPE;

typedef union _Dbp_POWER_STATE {
    Dbp_SYSTEM_POWER_STATE SystemState;
    Dbp_DEVICE_POWER_STATE DeviceState;
} Dbp_POWER_STATE, *Dbp_PPOWER_STATE;

typedef struct _Dbp_Power {
    ULONG SystemContext;
    Dbp_POWER_STATE_TYPE Type;
    Dbp_POWER_STATE State;
    Dbp_POWER_ACTION ShutdownType;
} Dbp_Power, *Dbp_PPower;

//////////////////////////////////////////////////////////////////////////////
//	DebugPrint globals

static BOOLEAN DebugPrintStarted = FALSE;
static char* DriverName = NULL;
static USHORT DriverNameLen = 0;

/////////////////////////////////////////////////////////////////////////////
//	DebugPrint Event structure (put in doubly-linked EventList)

typedef struct _DEBUGPRINT_EVENT
{
	LIST_ENTRY ListEntry;
	ULONG Len;
	UCHAR EventData[1];
} DEBUGPRINT_EVENT, *PDEBUGPRINT_EVENT;

//////////////////////////////////////////////////////////////////////////////
//	Globals to communicate with our system thread

PVOID ThreadObjectPointer=NULL;	// Thread pointer
BOOLEAN ExitNow;				// Set to cause thread to exit
KEVENT ThreadEvent;				// Set to make thread look at ExitNow.
LIST_ENTRY EventList;			// Doubly-linked list of written Events
KSPIN_LOCK EventListLock;		// Spin lock to guard access to EventList
KEVENT ThreadExiting;			// Set when thread exiting

void DebugPrintSystemThread( IN PVOID Context);
NTSTATUS OpenDebugPrintDriver( HANDLE* pDebugPrintDeviceHandle);

//////////////////////////////////////////////////////////////////////////////
//	DebugPrint local functions

HANDLE OpenDebugPrint();
void CloseDebugPrint( HANDLE h);
void DebugSprintf( char* buffer, int max, const char* format, va_list marker);
USHORT ANSIstrlen( char* str);
void ClearEvents();

//////////////////////////////////////////////////////////////////////////////
//	DebugPrintInit:		Initialise DebugPrint
//						Connect to DebugPrint driver at \Device\PHDDebugPrint
//
//	IRQL PASSIVE_LEVEL

void DebugPrintInit(char* _DriverName)
{
	HANDLE threadHandle;
	NTSTATUS status;

	// Copy the driver's name out of INIT code segment
	DriverNameLen = 1 + ANSIstrlen(_DriverName);
	DriverName = (char*)ExAllocatePool(NonPagedPool,DriverNameLen);
	if( DriverName==NULL) return;
	RtlCopyMemory( DriverName, _DriverName, DriverNameLen);

	/////////////////////////////////////////////////////////////////////////
	// Prepare for thread start

	ExitNow = FALSE;
	KeInitializeEvent(&ThreadEvent, SynchronizationEvent, FALSE);
	KeInitializeEvent(&ThreadExiting, SynchronizationEvent, FALSE);
	// Initialise event list
	KeInitializeSpinLock(&EventListLock);
	InitializeListHead(&EventList);

	/////////////////////////////////////////////////////////////////////////
	// Start system thread to write events to DebugPrint driver

	status = PsCreateSystemThread( &threadHandle, THREAD_ALL_ACCESS, NULL, NULL, NULL,
									DebugPrintSystemThread, NULL);
	if( !NT_SUCCESS(status))
		return;

	/////////////////////////////////////////////////////////////////////////
	// Save a pointer to thread and close handle.

	status = ObReferenceObjectByHandle( threadHandle, THREAD_ALL_ACCESS, NULL, KernelMode,
										&ThreadObjectPointer, NULL);

	if( NT_SUCCESS(status))
		ZwClose(threadHandle);
	else
	{
		// Uh oh... force thread to exit
		ExitNow = TRUE;
		KeSetEvent( &ThreadEvent, 0, FALSE);
		return;
	}

	DebugPrintStarted = TRUE;

	// Send event that we've started logging
	DebugPrintMsg("DebugPrint logging started");
}

//////////////////////////////////////////////////////////////////////////////
//	DebugPrintClose:	Close connection to DebugPrint
//
//	IRQL PASSIVE_LEVEL

void DebugPrintClose()
{
	if( !DebugPrintStarted) return;

	DebugPrintMsg("DebugPrint logging ended");
	DebugPrintStarted = FALSE;
	
	// Tell thread to stop, and wait for it to stop
	ExitNow = TRUE;
	KeSetEvent( &ThreadEvent, 0, FALSE);
	KeWaitForSingleObject( &ThreadExiting, Executive, KernelMode, FALSE, NULL);

	// Dereference thread object
	if( ThreadObjectPointer!=NULL)
	{
		ObDereferenceObject(&ThreadObjectPointer);
		ThreadObjectPointer = NULL;
	}
	
	// Release our copy of DriverName
	if( DriverName!=NULL)
		ExFreePool(DriverName);
//	ClearEvents();
}

//////////////////////////////////////////////////////////////////////////////
//	DebugPrintMsg:	Send message event to DebugPrint
//
//	IRQL <= DISPATCH_LEVEL

void DebugPrintMsg(char* Msg)
{
	LARGE_INTEGER Now;
	TIME_FIELDS NowTF;
	USHORT MsgLen;
	ULONG EventDataLen, len;
	PDEBUGPRINT_EVENT pEvent;

	if( !DebugPrintStarted || DriverName==NULL) return;

	// Get current time
	KeQuerySystemTime(&Now);
//	LARGE_INTEGER NowLocal;
//	ExSystemTimeToLocalTime( &Now, &NowLocal);	// NT only
//	RtlTimeToTimeFields( &NowLocal, &NowTF);
	RtlTimeToTimeFields( &Now, &NowTF);

	// Get size of Msg and complete event
	MsgLen = ANSIstrlen(Msg)+1;
	EventDataLen = sizeof(TIME_FIELDS) + DriverNameLen + MsgLen;
	len = sizeof(LIST_ENTRY)+sizeof(ULONG)+EventDataLen;

	// Allocate event buffer
	pEvent = (PDEBUGPRINT_EVENT)ExAllocatePool(NonPagedPool,len);
	if( pEvent!=NULL)
	{
		PUCHAR buffer = (PUCHAR)pEvent->EventData;
		// Copy event info to buffer
		RtlCopyMemory( buffer, &NowTF, sizeof(TIME_FIELDS));
		buffer += sizeof(TIME_FIELDS);
		RtlCopyMemory( buffer, DriverName, DriverNameLen);
		buffer += DriverNameLen;
		RtlCopyMemory( buffer, Msg, MsgLen);

		// Insert event into event list for processing by system thread
		pEvent->Len = EventDataLen;
		ExInterlockedInsertTailList(&EventList,&pEvent->ListEntry,&EventListLock);
	}
}

//////////////////////////////////////////////////////////////////////////////
//*	DebugPrintVA:	Implement DebugPrint calls

void DebugPrintVA(int max, const char* format, va_list marker)
{
	char* Msg;
	if( !DebugPrintStarted) return;
	Msg = (char*)ExAllocatePool(NonPagedPool,max);
	if( Msg==NULL)
	{
		DebugPrintMsg("DebugPrint: Could not allocate buffer");
		return;
	}
	DebugSprintf(Msg,max,format,marker);
	DebugPrintMsg(Msg);
	ExFreePool(Msg);
}
#endif // DODEBUGPRINT

//////////////////////////////////////////////////////////////////////////////
//	DebugPrint:	Formatted print to DebugPrint, allocating own print buffer
//
//	IRQL <= DISPATCH_LEVEL

void DebugPrint(const char* format, ... )
{
#if DODEBUGPRINT
	va_list marker;
	if( !DebugPrintStarted) return;
	va_start(marker,format);
	DebugPrintVA(100,format,marker);
#endif // DODEBUGPRINT
}

//////////////////////////////////////////////////////////////////////////////
//	DebugPrint:	Formatted print to DebugPrint, giving size of buffer to allocate
//
//	IRQL <= DISPATCH_LEVEL

void DebugPrint2(int max, const char* format, ... )
{
#if DODEBUGPRINT
	va_list marker;
	if( !DebugPrintStarted) return;
	va_start(marker,format);
	DebugPrintVA(max,format,marker);
#endif // DODEBUGPRINT
}

#if DODEBUGPRINT
//////////////////////////////////////////////////////////////////////////////
//	IRP Major and Minor function names

static char* IrpMajorFunctionNames[] =
{
	"IRP_MJ_CREATE",
	"IRP_MJ_CREATE_NAMED_PIPE",
	"IRP_MJ_CLOSE",
	"IRP_MJ_READ",
	"IRP_MJ_WRITE",
	"IRP_MJ_QUERY_INFORMATION",
	"IRP_MJ_SET_INFORMATION",
	"IRP_MJ_QUERY_EA",
	"IRP_MJ_SET_EA",
	"IRP_MJ_FLUSH_BUFFERS",
	"IRP_MJ_QUERY_VOLUME_INFORMATION",
	"IRP_MJ_SET_VOLUME_INFORMATION",
	"IRP_MJ_DIRECTORY_CONTROL",
	"IRP_MJ_FILE_SYSTEM_CONTROL",
	"IRP_MJ_DEVICE_CONTROL",
	"IRP_MJ_INTERNAL_DEVICE_CONTROL",
	"IRP_MJ_SHUTDOWN",
	"IRP_MJ_LOCK_CONTROL",
	"IRP_MJ_CLEANUP",
	"IRP_MJ_CREATE_MAILSLOT",
	"IRP_MJ_QUERY_SECURITY",
	"IRP_MJ_SET_SECURITY",
	"IRP_MJ_POWER",
	"IRP_MJ_SYSTEM_CONTROL",
	"IRP_MJ_DEVICE_CHANGE",
	"IRP_MJ_QUERY_QUOTA",
	"IRP_MJ_SET_QUOTA",
	"IRP_MJ_PNP",
};
static ULONG NUM_IrpMajorFunctionNames = sizeof(IrpMajorFunctionNames)/sizeof(char*);

static char* PnPIrpMinorFunctionNames[] =
{
	"IRP_MN_START_DEVICE",
	"IRP_MN_QUERY_REMOVE_DEVICE",
	"IRP_MN_REMOVE_DEVICE",
	"IRP_MN_CANCEL_REMOVE_DEVICE",
	"IRP_MN_STOP_DEVICE",
	"IRP_MN_QUERY_STOP_DEVICE",
	"IRP_MN_CANCEL_STOP_DEVICE",
	"IRP_MN_QUERY_DEVICE_RELATIONS",
	"IRP_MN_QUERY_INTERFACE",
	"IRP_MN_QUERY_CAPABILITIES",
	"IRP_MN_QUERY_RESOURCES",
	"IRP_MN_QUERY_RESOURCE_REQUIREMENTS",
	"IRP_MN_QUERY_DEVICE_TEXT",
	"IRP_MN_FILTER_RESOURCE_REQUIREMENTS",
	"Nowt",
	"IRP_MN_READ_CONFIG",
	"IRP_MN_WRITE_CONFIG",
	"IRP_MN_EJECT",
	"IRP_MN_SET_LOCK",
	"IRP_MN_QUERY_ID",
	"IRP_MN_QUERY_PNP_DEVICE_STATE",
	"IRP_MN_QUERY_BUS_INFORMATION",
	"IRP_MN_DEVICE_USAGE_NOTIFICATION",
	"IRP_MN_SURPRISE_REMOVAL",
	"IRP_MN_QUERY_LEGACY_BUS_INFORMATION",
};
static ULONG NUM_PnPIrpMinorFunctionNames = sizeof(PnPIrpMinorFunctionNames)/sizeof(char*);

static char* PowerIrpMinorFunctionNames[] =
{
	"IRP_MN_WAIT_WAKE",
	"IRP_MN_POWER_SEQUENCE",
	"IRP_MN_SET_POWER",
	"IRP_MN_QUERY_POWER",
};
static ULONG NUM_PowerIrpMinorFunctionNames = sizeof(PowerIrpMinorFunctionNames)/sizeof(char*);

static char* WMIIrpMinorFunctionNames[] =
{
	"IRP_MN_QUERY_ALL_DATA",
	"IRP_MN_QUERY_SINGLE_INSTANCE",
	"IRP_MN_CHANGE_SINGLE_INSTANCE",
	"IRP_MN_CHANGE_SINGLE_ITEM",
	"IRP_MN_ENABLE_EVENTS",
	"IRP_MN_DISABLE_EVENTS",
	"IRP_MN_ENABLE_COLLECTION",
	"IRP_MN_DISABLE_COLLECTION",
	"IRP_MN_REGINFO",
	"IRP_MN_EXECUTE_METHOD",
};
static ULONG NUM_WMIIrpMinorFunctionNames = sizeof(WMIIrpMinorFunctionNames)/sizeof(char*);

static char* PowerSystemStates[] =
{
    "PowerSystemUnspecified",
    "PowerSystemWorking",
    "PowerSystemSleeping1",
    "PowerSystemSleeping2",
    "PowerSystemSleeping3",
    "PowerSystemHibernate",
    "PowerSystemShutdown",
};
static int NUM_PowerSystemStates = sizeof(PowerSystemStates)/sizeof(char*);

static char* PowerDeviceStates[] =
{
    "PowerDeviceUnspecified",
    "PowerDeviceD0",
    "PowerDeviceD1",
    "PowerDeviceD2",
    "PowerDeviceD3",
};
static int NUM_PowerDeviceStates = sizeof(PowerDeviceStates)/sizeof(char*);

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//*	All these PrintXxx routines return TRUE if the buffer is filled
//*	Safe way to put a character in a buffer

#define PHDput(ch) if( (*pbufpos)>=max) return TRUE; else buffer[(*pbufpos)++] = (ch)

/////////////////////////////////////////////////////////////////////////////
//	Digits for decimal and hex conversions

static char hexdigits[] = "0123456789ABCDEF";

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////

BOOLEAN PrintChar( char* buffer, int max, int* pbufpos, char ch)
{
	PHDput(ch);
	return FALSE;
}

/////////////////////////////////////////////////////////////////////////////

BOOLEAN PrintULONG( char* buffer, int max, int* pbufpos, ULONG v)
{
	int digits;
	ULONG v2;
	int digno;

	if( v==0)
	{
		PHDput('0');
		return FALSE;
	}
	// Get number of digits
	digits = 0;
	v2 = v;
	while(v2!=0)
	{
		v2 /= 10;
		digits++;
	}
	// Write out
	(*pbufpos) += digits;
	for( digno=1;digno<=digits;digno++)
	{
		char ch = hexdigits[v%10];
		if( (*pbufpos)-digno<max) buffer[(*pbufpos)-digno] = ch;
		v /= 10;
	}
	return FALSE;
}

/////////////////////////////////////////////////////////////////////////////

BOOLEAN PrintInt( char* buffer, int max, int* pbufpos, int v)
{
	if( v<0)
	{
		PHDput('-');
		v = -v;
	}
	return PrintULONG( buffer, max, pbufpos, v);
}

/////////////////////////////////////////////////////////////////////////////

BOOLEAN PrintULONG64( char* buffer, int max, int* pbufpos, unsigned __int64 v)
{
	int digits;
	unsigned __int64 v2;
	int digno;

	if( v==0)
	{
		PHDput('0');
		return FALSE;
	}
	// Get number of digits
	digits = 0;
	v2 = v;
	while(v2!=0)
	{
		v2 /= 10;
		digits++;
	}
	// Write out
	(*pbufpos) += digits;
	for( digno=1;digno<=digits;digno++)
	{
		char ch = hexdigits[v%10];
		if( (*pbufpos)-digno<max) buffer[(*pbufpos)-digno] = ch;
		v /= 10;
	}
	return FALSE;
}

/////////////////////////////////////////////////////////////////////////////

BOOLEAN PrintInt64( char* buffer, int max, int* pbufpos, __int64 v)
{
	if( v<0)
	{
		PHDput('-');
		v = -v;
	}
	return PrintULONG64( buffer, max, pbufpos, v);
}

/////////////////////////////////////////////////////////////////////////////

BOOLEAN PrintULONGhex( char* buffer, int max, int* pbufpos, ULONG v, int FormatSize)
{
	ULONG mask = 0xF0000000;
	int shift = 28;
	int digno;
	if( FormatSize>0 && FormatSize<8)
	{
		mask >>= 4*(8-FormatSize);
		shift -= 4*(8-FormatSize);
	}
	else
		FormatSize = 8;
	for( digno=0;digno<FormatSize;digno++)
	{
		int digit = (v&mask)>>shift;
		PHDput(hexdigits[digit]);
		mask >>= 4;
		shift -= 4;
	}
	return FALSE;
}

/////////////////////////////////////////////////////////////////////////////

BOOLEAN PrintANSIString( char* buffer, int max, int* pbufpos, char* s, int FormatSize)
{
	char ch;
	BOOLEAN sized = (FormatSize>0);
	while( ch=*s++)
	{
		PHDput(ch);
		if( sized && (--FormatSize==0))
			break;
	}
	return FALSE;
}

/////////////////////////////////////////////////////////////////////////////

BOOLEAN PrintWideString( char* buffer, int max, int* pbufpos, wchar_t* ws, int FormatSize)
{
	wchar_t ch;
	BOOLEAN sized = (FormatSize>0);
	while( ch=*ws++)
	{
		PHDput((char)ch);
		if( sized && (--FormatSize==0))
			break;
	}
	return FALSE;
}

/////////////////////////////////////////////////////////////////////////////

BOOLEAN PrintUnicodeString( char* buffer, int max, int* pbufpos, PUNICODE_STRING pus)
{
	int uslen = (pus->Length) >> 1;
	wchar_t* ws = pus->Buffer;
	int chno;
	for( chno=0;chno<uslen;chno++)
	{
		wchar_t ch = *ws++;
		if( ch==L'\0') break;
		PHDput((char)ch);
	}

	return FALSE;
}

/////////////////////////////////////////////////////////////////////////////

BOOLEAN PrintIrp( char* buffer, int max, int* pbufpos, PIRP Irp)
{
	PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
	ULONG MajorFunction = IrpStack->MajorFunction;
	ULONG MinorFunction = IrpStack->MinorFunction;
	if( MajorFunction<NUM_IrpMajorFunctionNames)
	{
		char* MajorFunctionName = IrpMajorFunctionNames[MajorFunction];
		char* MinorFunctionName = NULL;
		char* ExtraDetails1 = NULL;
		char* ExtraDetails2 = NULL;

		if( PrintANSIString(buffer,max,pbufpos,MajorFunctionName,0)) return TRUE;

		switch(MajorFunction)
		{
		case Dbp_IRP_MJ_PNP:
			if( MinorFunction<NUM_PnPIrpMinorFunctionNames)
				MinorFunctionName = PnPIrpMinorFunctionNames[MinorFunction];
			else
			{
				PHDput(':');
				if( PrintULONGhex(buffer,max,pbufpos,MinorFunction,8)) return TRUE;
			}
			if( MinorFunction==Dbp_IRP_MN_QUERY_DEVICE_RELATIONS)
			{
				Dbp_PQueryDeviceRelations pQueryDeviceRelations= (Dbp_PQueryDeviceRelations)&IrpStack->Parameters.Read.Length;
				switch( pQueryDeviceRelations->Type)
				{
				case Dbp_BusRelations:			ExtraDetails1 = "BusRelations"; break;
				case Dbp_EjectionRelations:		ExtraDetails1 = "EjectionRelations"; break;
				case Dbp_PowerRelations:		ExtraDetails1 = "PowerRelations"; break;
				case Dbp_RemovalRelations:		ExtraDetails1 = "RemovalRelations"; break;
				case Dbp_TargetDeviceRelation:	ExtraDetails1 = "TargetDeviceRelation"; break;
				}
			}
			break;
		case Dbp_IRP_MJ_POWER:
			if( MinorFunction<NUM_PowerIrpMinorFunctionNames)
				MinorFunctionName = PowerIrpMinorFunctionNames[MinorFunction];
			if( MinorFunction==Dbp_IRP_MN_SET_POWER || MinorFunction==Dbp_IRP_MN_QUERY_POWER)
			{
				Dbp_PPower pPower = (Dbp_PPower)&IrpStack->Parameters.Read.Length;
				Dbp_POWER_STATE PowerState = pPower->State;
				ExtraDetails1 = (MinorFunction==Dbp_IRP_MN_SET_POWER ? "Set Power" : "Query Power");
				if( pPower->Type==Dbp_SystemPowerState)
				{
					if( PowerState.SystemState<NUM_PowerSystemStates)
						ExtraDetails2 = PowerSystemStates[PowerState.SystemState];
				}
				else
				{
					if( PowerState.DeviceState<NUM_PowerDeviceStates)
						ExtraDetails2 = PowerDeviceStates[PowerState.DeviceState];
				}
			}
			break;
		case Dbp_IRP_MJ_SYSTEM_CONTROL:
			if( MinorFunction<NUM_WMIIrpMinorFunctionNames)
				MinorFunctionName = WMIIrpMinorFunctionNames[MinorFunction];
			break;
		}
		if( MinorFunctionName!=NULL)
		{
			PHDput(':');
			if( PrintANSIString(buffer,max,pbufpos,MinorFunctionName,0)) return TRUE;
		}
		if( ExtraDetails1!=NULL)
		{
			PHDput(' ');
			if( PrintANSIString(buffer,max,pbufpos,ExtraDetails1,0)) return TRUE;
		}
		if( ExtraDetails2!=NULL)
		{
			PHDput(' ');
			if( PrintANSIString(buffer,max,pbufpos,ExtraDetails2,0)) return TRUE;
		}
	}
	return FALSE;
}

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//*	PHDsprintf:	Write formatted data to a string
//				PrintXxx routines used to do prints for each type
//				Give up as soon as end of buffer reached

#define PHD_va_arg(ap,t,v)	t v = va_arg(ap,t)

void DebugSprintf( char* buffer, int max, const char* format, va_list marker)
{
	int bufpos = 0;
	char ch;
	// Go through each format character
	while(ch=*format++)
	{
		int FormatSize = 0;
		if( ch!='%')
		{
			if( PrintChar(buffer,max,&bufpos,ch)) goto done;
			continue;
		}
		if( (ch=*format++) == '\0')
			break;
		if( ch=='*')
		{
			PHD_va_arg(marker,int,size);
			if( size>0)
				FormatSize = size;
			if( (ch=*format++) == '\0')
				break;
		}
		else if( ch>='1' && ch<='9')
		{
			FormatSize = 0;
			do
			{
				FormatSize = (FormatSize*10) + ch-'0';
				if( (ch=*format++) == '\0')
					break;
			}
			while( ch>='1' && ch<='9');
		}
		// Switch on specification character
		switch( ch)
		{
		//	ANSI char
		case 'c':
		{
			PHD_va_arg(marker,char,ch);
			if( PrintChar(buffer,max,&bufpos,ch)) goto done;
			break;
		}
		//	Wide char
		case 'C':
		{
			PHD_va_arg(marker,wchar_t,ch);
			if( PrintChar(buffer,max,&bufpos,(char)ch)) goto done;
			break;
		}
		//	Integer
		case 'd':
		case 'i':
		{
			PHD_va_arg(marker,int,i);
			if( PrintInt(buffer,max,&bufpos,i)) goto done;
			break;
		}
		//	__int64 in hex
		case 'D':
		{
			PHD_va_arg(marker,__int64,i64);
			if( PrintInt64(buffer,max,&bufpos,i64)) goto done;
			break;
		}
		//	__int64 in hex
		case 'l':
		{
			PHD_va_arg(marker,__int64,i64);
			LARGE_INTEGER li;
			li.QuadPart = i64;
			if( FormatSize==0) FormatSize=16;
			if( FormatSize>8)
			{
				if( PrintULONGhex(buffer,max,&bufpos,li.HighPart,FormatSize-8)) goto done;
			}
			if( PrintULONGhex(buffer,max,&bufpos,li.LowPart,FormatSize)) goto done;
			break;
		}
		//	LARGE_INTEGER in hex
		case 'L':
		{
			PHD_va_arg(marker,LARGE_INTEGER,li);
			if( FormatSize==0) FormatSize=16;
			if( FormatSize>8)
			{
				if( PrintULONGhex(buffer,max,&bufpos,li.HighPart,FormatSize-8)) goto done;
			}
			if( PrintULONGhex(buffer,max,&bufpos,li.LowPart,FormatSize)) goto done;
			break;
		}
		//	ULONG
		case 'u':
		{
			PHD_va_arg(marker,ULONG,uv);
			if( PrintULONG(buffer,max,&bufpos,uv)) goto done;
			break;
		}
		// ULONG as hex
		case 'x':
		{
			PHD_va_arg(marker,ULONG,uv);
			if( PrintULONGhex(buffer,max,&bufpos,uv,FormatSize)) goto done;
			break;
		}
		//	ANSI string
		case 's':
		{
			PHD_va_arg(marker,char*,s);
			if( PrintANSIString(buffer,max,&bufpos,s,FormatSize)) goto done;
			break;
		}
		//	Wide string
		case 'S':
		{
			PHD_va_arg(marker,wchar_t*,ws);
			if( PrintWideString(buffer,max,&bufpos,ws,FormatSize)) goto done;
			break;
		}
		//	PUNICODE_STRING
		case 'T':
		{
			PHD_va_arg(marker,PUNICODE_STRING,pus);
			if( PrintUnicodeString(buffer,max,&bufpos,pus)) goto done;
			break;
		}
		//	PIRP
		case 'I':
		{
			PHD_va_arg(marker,PIRP,Irp);
			if( PrintIrp(buffer,max,&bufpos,Irp)) goto done;
			break;
		}
		default:
			if( PrintChar(buffer,max,&bufpos,ch)) goto done;
		}
	}

	// NULL terminate string
	PrintChar(buffer,max,&bufpos,'\0');
done:
	// Ensure string terminated
	buffer[max-1] = '\0';
}

//////////////////////////////////////////////////////////////////////////////
//*	ANSIstrlen:	Return length of null terminated ANSI string

USHORT ANSIstrlen( char* str)
{
	USHORT len = 0;
	for(;*str++!='\0';)
		len++;
	return len;
}

/////////////////////////////////////////////////////////////////////////////
//*	DebugPrintSystemThread:
//
// Description:
//		System thread to print device events.
//		Check for events every second, and wait for ThreadEvent ExitNow
//
// IRQL:
//		<= APC_LEVEL_IRQL
//
// Arguments:
//		Context has no meaning
//
// Return Value:
//		(None)

void DebugPrintSystemThread( IN PVOID Context)
{
	HANDLE DebugPrintDeviceHandle = NULL;
	NTSTATUS status;
	LARGE_INTEGER OneSecondTimeout;
	LARGE_INTEGER ByteOffset;

	/////////////////////////////////////////////////////////////////////////
	// Lower thread priority

	KeSetPriorityThread( KeGetCurrentThread(), LOW_REALTIME_PRIORITY);

	/////////////////////////////////////////////////////////////////////////
	// Attempt to open DebugPrt driver for 5 mins

	status = OpenDebugPrintDriver( &DebugPrintDeviceHandle);
	if( !NT_SUCCESS(status) || DebugPrintDeviceHandle==NULL)
		goto exit1;
	
	/////////////////////////////////////////////////////////////////////////
	// Set up timeout and byte offset values
	
	OneSecondTimeout.QuadPart = -1i64 * 1000000i64 * 10i64;
	ByteOffset.QuadPart = 0i64;

	/////////////////////////////////////////////////////////////////////////
	// Loop waiting for events or ExitNow to go TRUE

	while(TRUE)
	{
		/////////////////////////////////////////////////////////////////////
		// Wait for a request from DebugPrintMsg or DebugPrintClose

		KeWaitForSingleObject( &ThreadEvent, Executive, KernelMode, FALSE, &OneSecondTimeout);

		/////////////////////////////////////////////////////////////////////
		//	Remove any Events from EventList and send to DebugPrint driver

		while(TRUE)
		{
			IO_STATUS_BLOCK IoStatus;
			PDEBUGPRINT_EVENT pEvent;
			ULONG EventDataLen;

			PLIST_ENTRY pListEntry = ExInterlockedRemoveHeadList( &EventList, &EventListLock);
			if( pListEntry==NULL)
				break;

			// Get event as DEBUGPRINT_EVENT
			pEvent = CONTAINING_RECORD( pListEntry, DEBUGPRINT_EVENT, ListEntry);

			// Get length of event data
			EventDataLen = pEvent->Len;

			// Send event to DebugPrint
			status = ZwWriteFile(	DebugPrintDeviceHandle, NULL, NULL, NULL,
									&IoStatus, pEvent->EventData, EventDataLen, &ByteOffset, NULL);
//			if( status!=STATUS_SUCCESS)
//				return;
//			if( IoStatus.Information != len)
//				return;

			// Free our event buffer
			ExFreePool(pEvent);
		}

		/////////////////////////////////////////////////////////////////////
		// DebugPrintClose called, so stop the thread now.

		if( ExitNow)
			break;
	}

	/////////////////////////////////////////////////////////////////////////
	// Tidy up and terminate thread
	ZwClose(DebugPrintDeviceHandle);
exit1:
	DebugPrintStarted = FALSE;
	ClearEvents();
	KeSetEvent( &ThreadExiting, 0, FALSE);
	PsTerminateSystemThread(STATUS_SUCCESS);
}

//////////////////////////////////////////////////////////////////////////////
//*	OpenDebugPrintDriver:	Attempt to open DebugPrt driver for 5 mins
//							Try opening every 20 seconds.
//							This gives DebugPrt time to start at boot time

NTSTATUS OpenDebugPrintDriver( HANDLE* pDebugPrintDeviceHandle)
{
	NTSTATUS status;
	UNICODE_STRING DebugPrintName;
	OBJECT_ATTRIBUTES ObjectAttributes;
	IO_STATUS_BLOCK IoStatus;
	LARGE_INTEGER OneSecondTimeout;
	int DelaySeconds = 0;

	// Set up timeout
	OneSecondTimeout.QuadPart = -1i64 * 1000000i64 * 10i64;

	// Make DebugPrint device name as UNICODE_STRING
	RtlInitUnicodeString( &DebugPrintName, L"\\Device\\PHDDebugPrint");

	// Make appropriate ObjectAttributes for ZwCreateFile
	InitializeObjectAttributes( &ObjectAttributes, &DebugPrintName, OBJ_CASE_INSENSITIVE, NULL, NULL);

	//////////////////////////////////////////////////////////////////////////
	// Attempt to open DebugPrt handle for 5 minutes

	while( DelaySeconds<5*60)
	{
		int Delay;

		//////////////////////////////////////////////////////////////////////
		// Open handle to DebugPrint device

		status = ZwCreateFile( pDebugPrintDeviceHandle,
			GENERIC_READ | GENERIC_WRITE,
			&ObjectAttributes,
			&IoStatus,
			0, // alloc size = none
			FILE_ATTRIBUTE_NORMAL,
			FILE_SHARE_READ|FILE_SHARE_WRITE,
			FILE_OPEN,
			0,
			NULL,  // eabuffer
			0 );   // ealength

		if( NT_SUCCESS(status) && *pDebugPrintDeviceHandle!=NULL)
			return status;

		//////////////////////////////////////////////////////////////////////
		// Wait for 20 seconds.

		for( Delay=20; Delay>0; Delay--)
		{
			KeWaitForSingleObject( &ThreadEvent, Executive, KernelMode, FALSE, &OneSecondTimeout);
			if( ExitNow)
				return status;
			DelaySeconds++;
		}
	}
	return status;
}

//////////////////////////////////////////////////////////////////////////////
//*	ClearEvents:	Clear any remaining events

void ClearEvents()
{
	while(TRUE)
	{
		PDEBUGPRINT_EVENT pEvent;
		PLIST_ENTRY pListEntry = ExInterlockedRemoveHeadList( &EventList, &EventListLock);
		if( pListEntry==NULL)
			break;
		pEvent = CONTAINING_RECORD( pListEntry, DEBUGPRINT_EVENT, ListEntry);
		ExFreePool(pEvent);
	}
}
//////////////////////////////////////////////////////////////////////////////

#endif  // DODEBUGPRINT

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
China China
From Shanghai, China

Comments and Discussions