You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
472 lines
9.6 KiB
472 lines
9.6 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
iopm.c
|
|
|
|
Abstract:
|
|
|
|
This module implements interfaces that support manipulation of i386
|
|
i/o access maps (IOPMs).
|
|
|
|
These entry points only exist on i386 machines.
|
|
|
|
Author:
|
|
|
|
Bryan M. Willman (bryanwi) 18-Sep-91
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "ki.h"
|
|
|
|
//
|
|
// Our notion of alignment is different, so force use of ours
|
|
//
|
|
|
|
#undef ALIGN_UP
|
|
#undef ALIGN_DOWN
|
|
#define ALIGN_DOWN(address,amt) ((ULONG)(address) & ~(( amt ) - 1))
|
|
#define ALIGN_UP(address,amt) (ALIGN_DOWN( (address + (amt) - 1), (amt) ))
|
|
|
|
//
|
|
// Note on synchronization:
|
|
//
|
|
// IOPM edits are always done by code running at DPC level on
|
|
// the processor whose TSS (map) is being edited.
|
|
//
|
|
// IOPM only affects user mode code. User mode code can never interrupt
|
|
// DPC level code, therefore, edits and user code never race.
|
|
//
|
|
|
|
|
|
//
|
|
// Define a structure to hold the map change info we pass to DPC's
|
|
//
|
|
|
|
typedef struct _MAPINFO {
|
|
PVOID MapSource;
|
|
PKPROCESS Process;
|
|
ULONG MapNumber;
|
|
USHORT MapOffset;
|
|
} MAPINFO, *PMAPINFO;
|
|
|
|
//
|
|
// Define forward referenced function prototypes.
|
|
//
|
|
|
|
VOID
|
|
KiSetIoMap(
|
|
PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SystemArgument1,
|
|
IN PVOID SystemArgument2
|
|
);
|
|
|
|
VOID
|
|
KiLoadIopmOffset(
|
|
IN PKIPI_CONTEXT SignalDone,
|
|
IN PVOID Parameter1,
|
|
IN PVOID Parameter2,
|
|
IN PVOID Parameter3
|
|
);
|
|
|
|
BOOLEAN
|
|
Ke386SetIoAccessMap (
|
|
ULONG MapNumber,
|
|
PKIO_ACCESS_MAP IoAccessMap
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The specified i/o access map will be set to match the
|
|
definition specified by IoAccessMap (i.e. enable/disable
|
|
those ports) before the call returns. The change will take
|
|
effect on all processors.
|
|
|
|
Ke386SetIoAccessMap does not give any process enhanced I/O
|
|
access, it merely defines a particular access map.
|
|
|
|
Arguments:
|
|
|
|
MapNumber - Number of access map to set. Map 0 is fixed.
|
|
|
|
IoAccessMap - Pointer to bitvector (64K bits, 8K bytes) which
|
|
defines the specified access map. Must be in
|
|
non-paged pool.
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful. FALSE if failure (attempt to set a map
|
|
which does not exist, attempt to set map 0)
|
|
|
|
--*/
|
|
|
|
{
|
|
MAPINFO MapInfo;
|
|
|
|
//
|
|
// Reject illegal requests
|
|
//
|
|
|
|
if ((MapNumber > IOPM_COUNT) || (MapNumber == IO_ACCESS_MAP_NONE)) {
|
|
return FALSE;
|
|
}
|
|
|
|
MapInfo.MapSource = IoAccessMap;
|
|
MapInfo.MapNumber = MapNumber;
|
|
MapInfo.Process = KeGetCurrentThread()->ApcState.Process;
|
|
|
|
KeGenericCallDpc (KiSetIoMap,
|
|
&MapInfo);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
KiSetIoMap(
|
|
PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SystemArgument1,
|
|
IN PVOID SystemArgument2
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
copy the specified map into this processor's TSS.
|
|
This procedure runs at IPI level.
|
|
|
|
Arguments:
|
|
|
|
Dpc - DPC used to initiate this call
|
|
DeferredContext - Context
|
|
SystemArgument1 - System context, Used to signal completion of this call
|
|
SystemArgument2 - System context
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PKPROCESS CurrentProcess;
|
|
PKPCR Pcr;
|
|
PKPRCB Prcb;
|
|
PVOID pt;
|
|
PMAPINFO MapInfo;
|
|
|
|
UNREFERENCED_PARAMETER (Dpc);
|
|
UNREFERENCED_PARAMETER (SystemArgument2);
|
|
|
|
MapInfo = DeferredContext;
|
|
|
|
//
|
|
// Copy the IOPM map and load the map for the current process.
|
|
// We only do this if the current process is running on this processor.
|
|
//
|
|
|
|
Pcr = KiPcr ();
|
|
Prcb = Pcr->Prcb;
|
|
CurrentProcess = Prcb->CurrentThread->ApcState.Process;
|
|
|
|
pt = &(Pcr->TSS->IoMaps[MapInfo->MapNumber-1].IoMap);
|
|
RtlCopyMemory (pt, MapInfo->MapSource, IOPM_SIZE);
|
|
Pcr->TSS->IoMapBase = CurrentProcess->IopmOffset;
|
|
|
|
//
|
|
// Signal that all processing has been done
|
|
//
|
|
|
|
KeSignalCallDpcDone (SystemArgument1);
|
|
|
|
return;
|
|
}
|
|
|
|
BOOLEAN
|
|
Ke386QueryIoAccessMap (
|
|
ULONG MapNumber,
|
|
PKIO_ACCESS_MAP IoAccessMap
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The specified i/o access map will be dumped into the buffer.
|
|
map 0 is a constant, but will be dumped anyway.
|
|
|
|
Arguments:
|
|
|
|
MapNumber - Number of access map to set. map 0 is fixed.
|
|
|
|
IoAccessMap - Pointer to buffer (64K bits, 8K bytes) which
|
|
is to receive the definition of the access map.
|
|
Must be in non-paged pool.
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful. FALSE if failure (attempt to query a map
|
|
which does not exist)
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG i;
|
|
PVOID Map;
|
|
KIRQL OldIrql;
|
|
PUCHAR p;
|
|
|
|
//
|
|
// Reject illegal requests
|
|
//
|
|
|
|
if (MapNumber > IOPM_COUNT) {
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Copy out the map
|
|
//
|
|
|
|
if (MapNumber == IO_ACCESS_MAP_NONE) {
|
|
|
|
//
|
|
// no access case, simply return a map of all 1s
|
|
//
|
|
|
|
p = (PUCHAR)IoAccessMap;
|
|
for (i = 0; i < IOPM_SIZE; i++) {
|
|
p[i] = (UCHAR)-1;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Raise to DISPATCH_LEVEL to obtain read access to the structure
|
|
//
|
|
|
|
KeRaiseIrql (DISPATCH_LEVEL, &OldIrql);
|
|
|
|
//
|
|
// normal case, just copy the bits
|
|
//
|
|
|
|
Map = (PVOID)&(KiPcr ()->TSS->IoMaps[MapNumber-1].IoMap);
|
|
RtlCopyMemory ((PVOID)IoAccessMap, Map, IOPM_SIZE);
|
|
|
|
//
|
|
// Restore IRQL.
|
|
//
|
|
|
|
KeLowerIrql (OldIrql);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
Ke386IoSetAccessProcess (
|
|
PKPROCESS Process,
|
|
ULONG MapNumber
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the i/o access map which controls user mode i/o access
|
|
for a particular process.
|
|
|
|
Arguments:
|
|
|
|
Process - Pointer to kernel process object describing the
|
|
process which for which a map is to be set.
|
|
|
|
MapNumber - Number of the map to set. Value of map is
|
|
defined by Ke386IoSetAccessProcess. Setting MapNumber
|
|
to IO_ACCESS_MAP_NONE will disallow any user mode i/o
|
|
access from the process.
|
|
|
|
Return Value:
|
|
|
|
TRUE if success, FALSE if failure (illegal MapNumber)
|
|
|
|
--*/
|
|
|
|
{
|
|
MAPINFO MapInfo;
|
|
USHORT MapOffset;
|
|
|
|
//
|
|
// Reject illegal requests
|
|
//
|
|
|
|
if (MapNumber > IOPM_COUNT) {
|
|
return FALSE;
|
|
}
|
|
|
|
MapOffset = KiComputeIopmOffset (MapNumber);
|
|
|
|
//
|
|
// Do the update on all processors at DISPATCH_LEVEL
|
|
//
|
|
|
|
MapInfo.Process = Process;
|
|
MapInfo.MapOffset = MapOffset;
|
|
|
|
KeGenericCallDpc (KiLoadIopmOffset,
|
|
&MapInfo);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
KiLoadIopmOffset(
|
|
PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SystemArgument1,
|
|
IN PVOID SystemArgument2
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Edit IopmBase of Tss to match that of currently running process.
|
|
|
|
Arguments:
|
|
|
|
Dpc - DPC used to initiate this call
|
|
DeferredContext - Context
|
|
SystemArgument1 - System context, Used to signal completion of this call
|
|
SystemArgument2 - System context
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
PKPCR Pcr;
|
|
PKPRCB Prcb;
|
|
PKPROCESS CurrentProcess;
|
|
PMAPINFO MapInfo;
|
|
|
|
UNREFERENCED_PARAMETER (Dpc);
|
|
UNREFERENCED_PARAMETER (SystemArgument2);
|
|
|
|
//
|
|
// Update IOPM field in TSS from current process
|
|
//
|
|
|
|
MapInfo = DeferredContext;
|
|
|
|
Pcr = KiPcr ();
|
|
Prcb = Pcr->Prcb;
|
|
CurrentProcess = Prcb->CurrentThread->ApcState.Process;
|
|
|
|
//
|
|
// Set the process IOPM offset first so its available to all.
|
|
// Any context swaps after this point will pick up the new value
|
|
// This store may occur multiple times but that doesn't matter
|
|
//
|
|
MapInfo->Process->IopmOffset = MapInfo->MapOffset;
|
|
|
|
Pcr->TSS->IoMapBase = CurrentProcess->IopmOffset;
|
|
|
|
//
|
|
// Signal that all processing has been done
|
|
//
|
|
|
|
KeSignalCallDpcDone (SystemArgument1);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
Ke386SetIOPL(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Gives IOPL to the specified process.
|
|
|
|
All threads created from this point on will get IOPL. The current
|
|
process will get IOPL. Must be called from context of thread and
|
|
process that are to have IOPL.
|
|
|
|
Iopl (to be made a boolean) in KPROCESS says all
|
|
new threads to get IOPL.
|
|
|
|
Iopl (to be made a boolean) in KTHREAD says given
|
|
thread to get IOPL.
|
|
|
|
N.B. If a kernel mode only thread calls this procedure, the
|
|
result is (a) poinless and (b) will break the system.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PKTHREAD Thread;
|
|
PKPROCESS Process2;
|
|
PKTRAP_FRAME TrapFrame;
|
|
CONTEXT Context;
|
|
|
|
//
|
|
// get current thread and Process2, set flag for IOPL in both of them
|
|
//
|
|
|
|
Thread = KeGetCurrentThread();
|
|
Process2 = Thread->ApcState.Process;
|
|
|
|
Process2->Iopl = 1;
|
|
Thread->Iopl = 1;
|
|
|
|
//
|
|
// Force IOPL to be on for current thread
|
|
//
|
|
|
|
TrapFrame = (PKTRAP_FRAME)((PUCHAR)Thread->InitialStack -
|
|
ALIGN_UP(sizeof(KTRAP_FRAME),KTRAP_FRAME_ALIGN) -
|
|
sizeof(FX_SAVE_AREA));
|
|
|
|
Context.ContextFlags = CONTEXT_CONTROL;
|
|
KeContextFromKframes(TrapFrame,
|
|
NULL,
|
|
&Context);
|
|
|
|
Context.EFlags |= (EFLAGS_IOPL_MASK & -1); // IOPL == 3
|
|
|
|
KeContextToKframes(TrapFrame,
|
|
NULL,
|
|
&Context,
|
|
CONTEXT_CONTROL,
|
|
UserMode);
|
|
|
|
return;
|
|
}
|