Has anyone worked with the NT I/O-permissions-map ? I have
run across some 'C' source code - freeware - that gets and sets
the I/O-permissions-map and allows ASM IN - OUT functions to work
directly under NT. Apperantly it allows cpu I/O instructions
permission to operate via the I/O permissions mechanism under
Win NT. I just wonder if any one has explored this. I understand
that this is a driver that changers the map but then any app that is
is attached (NT knows the app has premission)can directly control
any port.

/****************************************************************
gwiopm.c Port I/O Permission Map manipulator

Gives direct port I/O access for specified ports to user-mode process
(ie: "regular" Win32 application written by mere mortals.)

Revision Level: See Rev Variable

98-05-23 GW Original modifications

Note: This code is adapted from a module called giveio.sys originally
written by Dale Roberts 8/30/95, published in May 96 Dr Dobbs Journal, see www.ddj.com.

Dir to paste into Build window:
cd \proj\DelHwr\gwiopm

*********************************************************************/
#include <ntddk.h>

#define DEVICE_NAME_STRING L"gwiopm"
#define IOPM_VERSION 110 // decimal
#define IOPM_TEST0 0x0123
#define IOPM_TEST1 0x1234
#define IOPM_TEST2 0x2345

// Device type -- in the "User Defined" range."
#define IOPMD_TYPE 0xF100 // used several places

// The IOCTL function codes from 0x800 to 0xFFF are for non-Microsoft use.
// LIOPM means "local I/O Permission Map" maintained by this driver.
//--------------------------
// Test functions
#define IOCTL_IOPMD_READ_TEST CTL_CODE(IOPMD_TYPE, 0x900, METHOD_BUFFERED, FILE_ANY_ACCESS ) // returns IOPM_TEST
#define IOCTL_IOPMD_READ_VERSION CTL_CODE(IOPMD_TYPE, 0x901, METHOD_BUFFERED, FILE_ANY_ACCESS ) // returns IOPM_VERSION
// Manipulate local IOPM
#define IOCTL_IOPMD_CLEAR_LIOPM CTL_CODE(IOPMD_TYPE, 0x910, METHOD_BUFFERED, FILE_ANY_ACCESS ) // set map to block perm on all I/O addresses
#define IOCTL_IOPMD_SET_LIOPM CTL_CODE(IOPMD_TYPE, 0x911, METHOD_BUFFERED, FILE_ANY_ACCESS ) // set a byte (8 ports-worth) in LIOPM
#define IOCTL_IOPMD_GET_LIOPMB CTL_CODE(IOPMD_TYPE, 0x912, METHOD_BUFFERED, FILE_ANY_ACCESS ) // get a byte from LIOPM (diagnostic)
#define IOCTL_IOPMD_GET_LIOPMA CTL_CODE(IOPMD_TYPE, 0x913, METHOD_BUFFERED, FILE_ANY_ACCESS ) // get entire array of current LIOPM
// Interact with kernel
#define IOCTL_IOPMD_ACTIVATE_KIOPM CTL_CODE(IOPMD_TYPE, 0x920, METHOD_BUFFERED, FILE_ANY_ACCESS ) // copy LIOPM to be active map
#define IOCTL_IOPMD_DEACTIVATE_KIOPM CTL_CODE(IOPMD_TYPE, 0x921, METHOD_BUFFERED, FILE_ANY_ACCESS ) // tell NT to forget map
#define IOCTL_IOPMD_QUERY_KIOPM CTL_CODE(IOPMD_TYPE, 0x922, METHOD_BUFFERED, FILE_ANY_ACCESS ) // get OS's IOPM into LIOPM?

#define GWIOPM_PARAMCOUNT 3 // for most functions
#define GWIOPM_PARAMCOUNT_BYTES GWIOPM_PARAMCOUNT * 4 // for most functions

//---------------------------------------------------------
// IOPM array.
// This holds 8K * 8 bits -> 64K bits of the IOPM
// 0 bit -> enables access
// 1 bit -> disables access for user mode process.
//---------------------------------------------------------
#define IOPM_SIZE 0x2000
typedef UCHAR IOPM[IOPM_SIZE];
IOPM *IOPM_local = 0; // local version to be copied to TSS

//---------------------------------------------------------
// Undocumented kernel functions to manipulate access map.
//---------------------------------------------------------
void Ke386SetIoAccessMap(int, IOPM *); // copies the passed map to the TSS.
// int: 1 copy buffer, 0 fill with 0xFF
void Ke386QueryIoAccessMap(int, IOPM *); // int: ??
void Ke386IoSetAccessProcess(PEPROCESS, int); // adjusts IOPM offset ptr to newly copied map
// int: 1 enable I/O, 0 disable I/O

/*------------------------------------------------------------------
Set the IOPM (I/O permission map) of the calling process so that it
is given full I/O access. Our IOPM_local[] array is all zeros, so
the IOPM will be all zeros. If OnFlag is 1, the process is given I/O
access. If it is 0, access is removed.
*********************************************************************/

//------------------------------------------------------
void disp_ACTIVATE_KIOPM(void)
//------------------------------------------------------
{
Ke386IoSetAccessProcess(PsGetCurrentProcess(), 1);
Ke386SetIoAccessMap(1, IOPM_local);
}
//------------------------------------------------------
void disp_DEACTIVATE_KIOPM(void)
//------------------------------------------------------
{
Ke386IoSetAccessProcess(PsGetCurrentProcess(), 0);
}


//------------------------------------------------------
void disp_QUERY_KIOPM(void)
//------------------------------------------------------
{
Ke386QueryIoAccessMap(1, IOPM_local);
}

//------------------------------------------------------
void disp_CLEAR_LIOPM(void)
//------------------------------------------------------
{
int n;
// Set local IOPM to all 1's
for (n = 0; n < IOPM_SIZE; n++) {
(*IOPM_local)[n] = 0xFF;
}
}
/*-------------------------------------------------------
Main dispatch routine
--------------------------------------------------------*/

//------------------------------------------------------
NTSTATUS gwiopm_Dispatch(
//------------------------------------------------------
IN PDEVICE_OBJECT DeviceObject,
IN PIRP pIrp
)
{
int Ix, B;
PIO_STACK_LOCATION pIrpStack;
NTSTATUS Status;
// NOTE: Use METHOD_BUFFERED ioctls.
PULONG pIOBuffer; // Pointer to transfer buffer
// (treated as an array of longs, unless otherwise case).
ULONG InBufferSize; // Amount of data avail. from caller.
ULONG OutBufferSize; // Max data that caller can accept.
ULONG OutByteCount; // Actual count of output bytes
ULONG IoControlCode; // Control code request to driver


pIrpStack = IoGetCurrentIrpStackLocation(pIrp);

// Set default return status
Status = STATUS_NOT_IMPLEMENTED;
OutByteCount = 0;

// Dispatch based on major function code.
switch (pIrpStack->MajorFunction) {
case IRP_MJ_CREATE:
// no special Create processing
Status = STATUS_SUCCESS;
break;
case IRP_MJ_CLOSE:
// no special open/close processing
Status = STATUS_SUCCESS;
break;
case IRP_MJ_DEVICE_CONTROL:

// Size of buffer containing data from application
InBufferSize = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;

// Size of buffer for data to be sent to application
OutBufferSize = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;

// NT copies inbuf here before entry and copies this to outbuf after
// return, for METHOD_BUFFERED IOCTL's.
pIOBuffer = (PULONG)pIrp->AssociatedIrp.SystemBuffer;

IoControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
switch (IoControlCode) {
//--------------------------------------------------------
// IOCTL command dispatch
//--------------------------------------------------------
//---------------------------
// Test functions
//---------------------------
case IOCTL_IOPMD_READ_TEST:
pIOBuffer[0] = IOPM_TEST0;
pIOBuffer[1] = IOPM_TEST1;
pIOBuffer[2] = IoControlCode;
OutByteCount = GWIOPM_PARAMCOUNT_BYTES;
Status = STATUS_SUCCESS;
break;
//---------------------------
case IOCTL_IOPMD_READ_VERSION:
pIOBuffer[0] = IOPM_VERSION;
pIOBuffer[2] = IoControlCode;
OutByteCount = GWIOPM_PARAMCOUNT_BYTES;
Status = STATUS_SUCCESS;
break;
//---------------------------
// Manipulate local IOPM (LIOPM)
//---------------------------
case IOCTL_IOPMD_CLEAR_LIOPM:
disp_CLEAR_LIOPM();
pIOBuffer[2] = IoControlCode;
OutByteCount = GWIOPM_PARAMCOUNT_BYTES;
Status = STATUS_SUCCESS;
break;
//---------------------------
case IOCTL_IOPMD_SET_LIOPM:
Ix = pIOBuffer[0] & 0x1FFF; // index, 0..0x1FFF
B = pIOBuffer[1] & 0xFF; // byte, 0..0xFF
(*IOPM_local)[Ix] = B;
pIOBuffer[2] = IoControlCode;
OutByteCount = GWIOPM_PARAMCOUNT_BYTES;
Status = STATUS_SUCCESS;
break;
//---------------------------
case IOCTL_IOPMD_GET_LIOPMB:
Ix = pIOBuffer[0] & 0x1FFF; // index, 0..0x1FFF
B = (*IOPM_local)[Ix];
pIOBuffer[1] = B & 0x000000FF; // byte.. 0..0xFF
pIOBuffer[2] = IoControlCode;
OutByteCount = GWIOPM_PARAMCOUNT_BYTES;
Status = STATUS_SUCCESS;
break;
//---------------------------
case IOCTL_IOPMD_GET_LIOPMA:
if (OutBufferSize < IOPM_SIZE) {
Status = STATUS_INVALID_PARAMETER;
} else {
for (Ix=0;Ix<IOPM_SIZE;Ix++) {
((PUCHAR)pIOBuffer)[Ix] = (*IOPM_local)[Ix];
}
// note, IoControlCode not echoed since buffer is filled with array
OutByteCount = IOPM_SIZE;
Status = STATUS_SUCCESS;
}
break;
//--------------------------------
// Interact with kernel IOPM (KIOPM)
//--------------------------------
case IOCTL_IOPMD_ACTIVATE_KIOPM:
disp_ACTIVATE_KIOPM();
pIOBuffer[2] = IoControlCode;
OutByteCount = GWIOPM_PARAMCOUNT_BYTES;
Status = STATUS_SUCCESS;
break;
//---------------------------
case IOCTL_IOPMD_DEACTIVATE_KIOPM:
disp_DEACTIVATE_KIOPM();
pIOBuffer[2] = IoControlCode;
OutByteCount = GWIOPM_PARAMCOUNT_BYTES;
Status = STATUS_SUCCESS;
break;
//---------------------------
case IOCTL_IOPMD_QUERY_KIOPM:
disp_QUERY_KIOPM();
pIOBuffer[2] = IoControlCode;
OutByteCount = GWIOPM_PARAMCOUNT_BYTES;
Status = STATUS_SUCCESS;
break;
//---------------------------
default:
pIOBuffer[2] = IoControlCode;
OutByteCount = GWIOPM_PARAMCOUNT_BYTES;
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
break;
}

// We're done with I/O request. Record the status of the I/O action.
pIrp->IoStatus.Status = Status;
pIrp->IoStatus.Information = OutByteCount;

// Don't boost priority when returning (since this took little time?)
IoCompleteRequest(pIrp, IO_NO_INCREMENT );

return Status;
}

//------------------------------------------------------
VOID gwiopm_Unload(IN PDRIVER_OBJECT DriverObject)
//------------------------------------------------------
{
WCHAR DOSNameBuffer[] = L"\\DosDevices\\" DEVICE_NAME_STRING;
UNICODE_STRING uniDOSString;

if(IOPM_local)
MmFreeNonCachedMemory(IOPM_local, sizeof(IOPM));

RtlInitUnicodeString(&uniDOSString, DOSNameBuffer);
IoDeleteSymbolicLink (&uniDOSString);
IoDeleteDevice(DriverObject->DeviceObject);
}

/*********************************************************************
Driver Entry routine.

This routine is called only once after the driver is initially
loaded into memory. It allocates everything necessary for the
driver's operation. In our case, it allocates memory for our IOPM
array. It also creates a symbolic link to the device driver. This allows
a user mode application to access our driver using the \\.\gwiopm
notation.
*********************************************************************/
NTSTATUS DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
PDEVICE_OBJECT deviceObject;
NTSTATUS status;
WCHAR NameBuffer[] = L"\\Device\\" DEVICE_NAME_STRING;
WCHAR DOSNameBuffer[] = L"\\DosDevices\\" DEVICE_NAME_STRING;
UNICODE_STRING uniNameString, uniDOSString;
int n;

//
// Allocate a buffer for the local IOPM and clear it to no-permissions
//
IOPM_local = MmAllocateNonCachedMemory(sizeof(IOPM));
if(IOPM_local == 0) return STATUS_INSUFFICIENT_RESOURCES;

disp_CLEAR_LIOPM();

//
// Set up device driver name and device object.
//
RtlInitUnicodeString(&uniNameString, NameBuffer);
RtlInitUnicodeString(&uniDOSString, DOSNameBuffer);

status = IoCreateDevice(DriverObject, 0, &uniNameString, IOPMD_TYPE, 0, FALSE, &deviceObject);

if(!NT_SUCCESS(status)) return status;

status = IoCreateSymbolicLink (&uniDOSString, &uniNameString);
if (!NT_SUCCESS(status)) return status;

// Initialize the Driver Object with driver's entry points.

DriverObject->MajorFunction[IRP_MJ_CREATE] = gwiopm_Dispatch;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = gwiopm_Dispatch;
DriverObject->DriverUnload = gwiopm_Unload;

return STATUS_SUCCESS;
}




------------------