📄 gwiopm_code.htm
字号:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>gwiopm.pas documentation</title>
</head>
<body bgcolor="#FFFFFF">
<table border="0" cellpadding="4" width="100%">
<tr>
<td width="50%"> <a href="http://www.wideman-one.com/"><img src="logo_small.gif" alt="wideman-one" border="0" align="top" WIDTH="164" HEIGHT="22"></a><em><small><small> </small></small><br>
<small><small>Last edit: <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%y-%m-%d" startspan -->98-06-18<!--webbot bot="Timestamp" endspan i-checksum="13341" --> Graham Wideman</small></small></em></td>
<td width="50%" valign="top" align="right"><h3 align="right">Delphi</h3>
</td>
</tr>
</table>
<table border="1" cellpadding="2" width="100%">
<tr>
<td><big><big><strong>gwiopm.pas and gwiopm.sys documentation</strong></big></big><br>
<em><small><small>Article created: 98-06-01</small></small><br>
<small><small>Minor edits: 98-06-18</small></small></em></td>
</tr>
</table>
<h3>Overview</h3>
<p>The basic model is shown below:</p>
<p><img src="iopm_tech.gif" alt="iopm_tech.gif (9789 bytes)" WIDTH="553" HEIGHT="396"></p>
<p>The keys to the whole picture are the kernel functions highlighted in yellow.
These are what our driver uses to command the NT kernel to install our desired I/O
permissions map. (Some comments on this below.)</p>
<p>The unit gwiopm.pas contains an object GWIOPM_Driver with a number of methods to
install the driver, prepare an I/O permissions map, hand that map to the driver, and then
from driver to kernel. </p>
<p>An I/O permissions map is 8K bytes in size, with each bit controlling access to one
port in the x86's 64K I/O port address space. Bit 0 of Byte 0 controls I/O address 0, and
so on. A "1" bit value disables access, a "0" value enables access.</p>
<p>There are other auxiliary functions to provide some diagnostics and general hacking
satisfaction.</p>
<table border="1" cellpadding="3" width="100%">
<tr>
<td width="263" valign="top"><strong>Task and </strong>GWIOPM_Driver<strong> function</strong></td>
<td width="590" valign="top"><strong>Description</strong></td>
</tr>
<tr>
<td width="263" valign="top"><strong>Connect to Service Control Manager</strong></td>
<td width="590" valign="top"> </td>
</tr>
<tr>
<td width="263" valign="top"><pre><small>OpenSCM: DWORD;
CloseSCM: DWORD;</small></pre>
</td>
<td width="590" valign="top">Open and close connection to Service Control Manager. Basic
function of OpenSCM is to get a handle to the SCM, which is retained by the GWIOPM_Driver
object for later use in the driver management functions.... </td>
</tr>
<tr>
<td width="263" valign="top"><strong>Manage Driver</strong></td>
<td width="590" valign="top"> </td>
</tr>
<tr>
<td width="263" valign="top"><pre><small>Install(newdriverpath: string): DWORD;
Start: DWORD;
Stop: DWORD;
Remove: DWORD;</small></pre>
</td>
<td width="590" valign="top">Functions to install, start, stop and remove driver.
Install() takes either a driver path or '' for default (gwiopm.sys in the application's
home directory.)</td>
</tr>
<tr>
<td width="263" valign="top"><strong>Device functions</strong></td>
<td width="590" valign="top"> </td>
</tr>
<tr>
<td width="263" valign="top"><pre><small>DeviceOpen: DWORD;
DeviceClose: DWORD;</pre>
</small></td>
<td width="590" valign="top">First you must open a device. This fetches a device handle
for the future use of GWIOPM_Driver's other driver functions. (Note that the device handle
is different from the SCM handle). Later, you must close the device if you want to
remove the driver. Note that closing the device or removing the driver does <em>not</em>
remove the IOPM that you may have provided to the NT kernel (though presumably the kernel
knows to forget about it after the application using it quits?)</td>
</tr>
<tr>
<td width="263" valign="top"><strong>Test functions</strong></td>
<td width="590" valign="top"> </td>
</tr>
<tr>
<td width="263" valign="top"><pre><small>IOCTL_IOPMD_READ_TEST
(var RetVal: DWORD): DWORD;
IOCTL_IOPMD_READ_VERSION
(var RetVal: DWORD): DWORD;</pre>
</small></td>
<td width="590" valign="top">Diagnostics to check that driver is installed and
functioning. READ_TEST returns a RetVal of $123 while READ_VERSION returns a decimal
number somewhere over 100 for version 1.x</td>
</tr>
<tr>
<td width="263" valign="top"><strong>Manipulate driver's local IOPM (LIOPM)</strong></td>
<td width="590" valign="top"> </td>
</tr>
<tr>
<td width="263" valign="top"><small><pre>IOCTL_IOPMD_CLEAR_LIOPM: DWORD;
IOCTL_IOPMD_SET_LIOPM
(Addr: Word; B: byte): DWORD;</pre>
</small></td>
<td width="590" valign="top">Clear the driver's preparatory map array, or set specific
bytes to particular values. </td>
</tr>
<tr>
<td width="263" valign="top"><pre><small>IOCTL_IOPMD_GET_LIOPMB
(Addr: Word; var B: byte): DWORD;
IOCTL_IOPMD_GET_LIOPMA(var A: TIOPM): DWORD;</pre>
</small></td>
<td width="590" valign="top">Fetch either a particular byte, or the whole map from the
driver. Note that this is the driver's map-in-preparation, not the one that the kernel is
actually using.</td>
</tr>
<tr>
<td width="263" valign="top"><strong><pre></strong><small>LIOPM_Set_Ports</small>
<small> (BeginPort: word; EndPort: word; </small>
<small> Enable: Boolean): DWORD;</small><strong></pre>
</strong></td>
<td width="590" valign="top">Enable/disable bits for specific ports. (Preferable to
calling <small>IOCTL_IOPMD_SET_LIOPM</small> if you only need to set or change a few
bits.)</td>
</tr>
<tr>
<td width="263" valign="top"><strong>Interact with kernel IOPM (KIOPM)</strong></td>
<td width="590" valign="top"> </td>
</tr>
<tr>
<td width="263" valign="top"><pre><small>IOCTL_IOPMD_ACTIVATE_KIOPM: DWORD;</small></pre>
</td>
<td width="590" valign="top">Give the driver's "local" (preparatory) map to the
kernel and make it the active one for our process.</td>
</tr>
<tr>
<td width="263" valign="top"><small><pre>IOCTL_IOPMD_DEACTIVATE_KIOPM: DWORD;</pre>
</small></td>
<td width="590" valign="top">Tell kernel to forget about our process-specific map.</td>
</tr>
<tr>
<td width="263" valign="top"><pre><small>IOCTL_IOPMD_QUERY_KIOPM: DWORD;</small></pre>
</td>
<td width="590" valign="top">Readback the kernel's map to the driver. (If you then use
GET_LIOPMB your app can see the map the kernel is currently using.)</td>
</tr>
<tr>
<td width="263" valign="top"> </td>
<td width="590" valign="top"> </td>
</tr>
<tr>
<td width="263" valign="top"><strong>Return values:</strong></td>
<td width="590" valign="top">Functions generally return ERROR_SUCCESS or other error code
that can be examined with the ErrorLookup function</td>
</tr>
<tr>
<td width="263" valign="top"><pre><small>ErrorLookup(ErrorNum: DWORD): string;</small></pre>
</td>
<td width="590" valign="top"> </td>
</tr>
</table>
<h3>Kernel Functions</h3>
<p>The NT kernel functions that are used by the gwiopm driver are poorly documented, so
their exact function is a matter of some speculation. They were partly sleuthed by Dale
Roberts, and I have experimented with them a little more. So here's what I think they do:</p>
<table border="1" cellpadding="4" width="100%">
<tr>
<td width="322" valign="top"><strong>Kernel function</strong></td>
<td width="448" valign="top"><strong>Description or speculation</strong></td>
</tr>
<tr>
<td width="322" valign="top"><pre><small>void </small>
<small>Ke386IoSetAccessProcess(PEPROCESS, int);</small></pre>
</td>
<td width="448" valign="top">This provides the identity of the current process (ie: your
application) to the kernel, and apparently lets the kernel know that we want to use a
special I/O permissions map for this process (presumably the kernel needs to reserve us
some space.) The int argument apparently enables (1) or disables (0) the special map
(or blanket enables/disables I/O for this process, I'm not sure which.)</td>
</tr>
<tr>
<td width="322" valign="top"><pre><small>void </small>
<small>Ke386SetIoAccessMap(int, IOPM *); </small></pre>
</td>
<td width="448" valign="top">This is the function that the driver uses to provide a new
map (8K bytes) to the kernel. The int argument chooses between:<br>
"1": copy our map... or... <br>
"0": fill kernel's map with 0xFF"<br>
Note that a 1 bit <em>in the map</em> disables access to a particular port, so the int=0
option effectively clears the kernel's map to all-disabled. </td>
</tr>
<tr>
<td width="322" valign="top"><pre><small>void </small>
<small>Ke386QueryIoAccessMap(int, IOPM *);</small></pre>
</td>
<td width="448" valign="top">This function copies the kernel's map back to the driver's
local map buffer. I have no idea what the int argument does, but when set to 1 it
works. Perhaps set to 0 it clears the driver's map to 0xFF's.</td>
</tr>
</table>
<p>In each case you can look at the gwiopm.c source to see how I used them. This
follows how Dale Roberts used them, with a little bit of extra experimentation on the
Query function.</p>
<h3>Further Adventures...</h3>
<p><strong>Client-specific IOPM: </strong>The gwiopm.sys driver was written with only a
single client application in mind. In fact the whole idea of bypassing NT's resource
arbitration/allocation philosophy and programming directly to the I/O ports
presupposes that only one application (or applications that are very friendly) will be
using the driver. However, it might make some sense to modestly redesign
gwiopm so that the local IOPM table is client-app specific, rather than global for all
clients of the driver. This could be done by defining a so-called "device
extension" to hold the client-by-client port-enable info. See the Art Baker reference
or the NT DDK samples.</p>
<hr>
<p><em>Go to:</em> <a href="http://www.wideman-one.com/"><img src="logo_small.gif" alt="wideman-one" border="0" align="top" WIDTH="164" HEIGHT="22"></a></p>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -