NOTE
For a detailed description of the Kernel PlugIn feature, and the related
development process and APIs, refer to the
WinDriver PCI User's Manual.
Beginning with version 10.3.0 of WinDriver, you can communicate with a
64-bit Kernel PlugIn driver from a 32-bit user-mode
application. To support such a configuration, you need to keep in mind the
following points:
- The application must open a handle to the Kernel PlugIn driver using
WDC_KernelPlugInOpen() (or the low-level
WD_KernelPlugInOpen() function, if you are
not using the WDC library).
The handle cannot be opened using one of the WDC device-open
functions (e.g., WDC_PciDeviceOpen()) by
calling it with the name of a Kernel PlugIn driver.
(In all Kernel PlugIn configurations, except for a
64-bit driver that interacts with a 32-bit
application, either of these methods can be used to open a handle to
the Kernel PlugIn from the application.)
- The Kernel PlugIn driver must implement a
KP_Open callback that correctly translates
the 32-bit data received from the user mode, into
64-bit kernel data.
The Kernel PlugIn driver's KP_Init()
function must set this callback in the
funcOpen_32_64 field of the
KP_INIT structure that it initializes.
(This field was added in version 10.3.0 of WinDriver.)
NOTE
The callback set in the KP_INIT
funcOpen_32_64 field, is called by
WinDriver when a 32-bit application opens a handle to a
Kernel PlugIn driver. This callback will hereby be referred to as
the funcOpen_32_64 callback.
The callback set in the KP_INIT
funcOpen field is the standard
KP_Open callback, which is called by
WinDriver whenever an application opens a Kernel PlugIn handle,
except for the specific configuration in which the
funcOpen_32_64 callback is used. This
callback will hereby be referred to as
the funcOpen callback.
When writing your Kernel PlugIn driver, you can select whether to
provide both of these callback types or just one of them —
depending on how you plan to build the driver and how you expect it to
be used. For example, if you are not planning to use the driver on a
64-bit operating system, you do not need to implement and
set funcOpen_32_64.
In version 10.3.0 and above of WinDriver, the generated DriverWizard
Kernel PlugIn projects, and the sample PCI Kernel PlugIn project
(kp_pci), are written so as to support all types of user-mode and Kernel
PlugIn configurations, including using a 32-bit application with a
64-bit Kernel PlugIn.
To modify code developed with earlier versions of WinDriver to afford the same
support, follow these steps:
-
In the user-mode code, do the following:
- Separate the steps of opening a handle to the device and
opening a handle to the Kernel PlugIn. In version 10.2.1 and
below of WinDriver, the sample and generated code used the
WDC_xxxDeviceOpen()
functions (e.g.,
WDC_PciDeviceOpen()) to open both
of these handles. As explained above, this method cannot be
used if you also wish to work with a 32-bit
application and a 64-bit Kernel PlugIn driver. If
your code uses this method, modify the call to
WDC_xxxDeviceOpen() so that you
pass NULL for the last two
parameters — pcKPDriverName
and pKPOpenData.
-
Use WDC_KernelPlugInOpen()
to open the handle to the Kernel PlugIn driver.
For the function's hDev parameter,
pass the same handle whose address was passed as the
phDev parameter of the device-open
function. (Note that here you are passing
hDev —
WDC_DEVICE_HANDLE — and not
&hDev —
WDC_DEVICE_HANDLE* — like in
the first parameter of
WDC_xxxDeviceOpen().)
For the pcKPDriverName parameter,
pass the name of your Kernel PlugIn driver (as previously done
for the equivalent device-open function parameter, if you used
it to also open the Kernel PlugIn handle).
For the pKPOpenData parameter, pass
the data you wish to pass down from the application to the
Kernel PlugIn (similar to the device-open function parameter of
the same name).
In the older WinDriver sample and generated code, the device
handle was passed as the open-data. However, to reduce the work
that would need to be done in the Kernel PlugIn to convert the
32-bit data to 64-bit, the newer code
now passes only the necessary information to the Kernel PlugIn;
we recommend that you do the same:
- Define the following types, to be used both by the
user-mode and Kernel PlugIn code; (in the sample and
generated code, these types are defined in the
xxx_lib.h file):
/* Device address description struct */
typedef struct {
DWORD dwNumAddrSpaces; /* Total number of device address spaces */
WDC_ADDR_DESC *pAddrDesc; /* Array of device address spaces information */
} PCI_DEV_ADDR_DESC;
- Allocate a variable of type
PCI_DEV_ADDR_DESC
and set its fields according to the information
returned by the previous call to the
WDC_xxxDeviceOpen()
function.
In the sample and generated code, this is done in the
xxx_lib.c file as shown below:
PCI_DEV_ADDR_DESC devAddrDesc;
PWDC_DEVICE pDev;
...
dwStatus = WDC_PciDeviceOpen(&hDev, pDeviceInfo, pDevCtx, NULL, NULL, NULL);
...
pDev = hDev;
devAddrDesc.dwNumAddrSpaces = pDev->dwNumAddrSpaces;
devAddrDesc.pAddrDesc = pDev->pAddrDesc;
WDC_KernelPlugInOpen(hDev, KP_PCI_DRIVER_NAME, &devAddrDesc);
-
In the Kernel PlugIn driver code, do the following:
-
Modify your funcOpen
callback: If you have changed the type of the open-data
that is passed from the user mode to the driver, you need to
adjust the implementation of your open-callback accordingly.
If your existing code was based on the sample or generated
Kernel PlugIn code in earlier versions of WinDriver, and you
have selected to pass the address of a
PCI_DEV_ADDR_DESC struct as your
Kernel PlugIn open-data — as recommended in
Step I.2
— modify your funcOpen
callback as follows:
-
Replace the
PWDC_DEVICE hDev;
definition with
PCI_DEV_ADDR_DESC *pDevAddrDesc;,
and replace instances of
WDC_DEVICE and
pDev in the function with
PCI_DEV_ADDR_DESC and
pDevAddrDesc, respectively.
-
Remove the temp variable
definition, and replace the two
COPY_FROM_USER calls (which
use the temp variable) with
the following call:
COPY_FROM_USER(pDevAddrDesc, pOpenData, dwSize);
- As an additional unrelated fix to previous sample and
generated WinDriver funcOpen implementations,
move the call to the library initialization function
(PCI_LibInit() in the PCI
sample / XXX_LibInit in the
generated DriverWizard code — where
XXX is the name of your
driver project) to the beginning of the function
— right after the variable declarations and
before the first call to the Kernel PlugIn trace
messages function (KP_PCI_Trace() in the PCI
sample / KP_XXX_Trace() in the wizard-generated
code).
- Create your funcOpen_32_64
callback: Copy your funcOpen
callback function, and rename it. The renamed function will be
modified to implement your
funcOpen_32_64 callback — for
opening a handle to a 64-bit Kernel PlugIn driver
from a 32-bit application.
In the
<WinDriver>/samples/pci_diag/kp_pci/kp_pci.c
sample, the funcOpen function is
named KP_PCI_Open, and the
funcOpen_32_64 function is named
KP_PCI_Open_32_64. The generated
DriverWizard Kernel PlugIn open functions are named in a
similar manner, except that "PCI" is replaced with your
selected driver project name.
NOTE
If you only plan to support a 32-bit application
and 64-bit Kernel PlugIn configuration, you can
skip this step, and in the next step modify your
KP_Open callback to use it as your
funcOpen_32_64 callback; then
assign this callback to the KP_INIT
funcOpen_32_64 field, instead of to
the funcOpen field. However, to
keep your code portable, it's best to implement both types of
callbacks.
-
Edit your Kernel PlugIn code to handle the translation of
the 32-bit data passed from the user mode,
into 64-bit kernel data:
- Add a 32-bit definition of the
Kernel PlugIn open-data type.
- In your funcOpen_32_64
callback, translate the 32-bit open-date
received from the user mode, into the equivalent
64-bit type.
For example, if your original code was based on the sample or
generated Kernel PlugIn code in earlier versions of WinDriver,
and you have selected to pass the address of a
PCI_DEV_ADDR_DESC struct as your
Kernel PlugIn open-data — as recommended in
Step I.2
— modify the code as follows:
- Add the following definitions at the beginning
of the file:
#define PTR32 DWORD
typedef struct WDC_DEV_ADDR_DESC_32B {
DWORD dwNumAddrSpaces; /* Total number of device address spaces */
PTR32 pAddrDesc; /* Array of device address spaces information */
} WDC_DEV_ADDR_DESC_32B, *PWDC_DEV_ADDR_DESC_32B;
- Modify your
funcOpen_32_64 callback
as follows:
- Add the following definition:
WDC_DEV_ADDR_DESC_32B devAddrDesc_32;
- Add the following lines after the
kpOpenCall
field assignments, in order to copy to the
kernel mode the 32-bit data that
was received from the user mode:
/* Copy device information sent from a 32-bit user application */
COPY_FROM_USER(&devAddrDesc_32, pOpenData, sizeof(PCI_DEV_ADDR_DESC_32B));
- Replace the following line —
COPY_FROM_USER(pDevAddrDesc,
pOpenData, dwSize);
— with these lines, in order to copy the
32-bit data into a
64-bit structure:
/* Copy the 32-bit data to a 64-bit struct */
pDevAddrDesc->dwNumAddrSpaces = devAddrDesc_32.dwNumAddrSpaces;
- Replace the second
COPY_FROM_USER
call —
COPY_FROM_USER(pAddrDesc,
pDevAddrDesc->pAddrDesc, dwSize);
— with the following:
COPY_FROM_USER(pAddrDesc, (PVOID)(KPTR)devAddrDesc_32.pAddrDesc, dwSize);
-
Update your KP_Init()
function: Notify WinDriver of your
funcOpen_32_64 callback, by
assigning your funcOpen_32_64
callback to the funcOpen_32_64
field of the KP_INIT struct that is
initialized in KP_Init():
kpInit->funcOpen_32_64 = <Your funcOpen_32_64 callback >;
For example, this is the assignment line from the updated
kp_pci.c sample:
kpInit->funcOpen_32_64 = KP_PCI_Open_32_64;
NOTE
If you select to only implement a
funcOpen_32_64 callback, and not to
implement a standard funcOpen
callback, remove the assignment to the KP_INIT
funcOpen field in
KP_Init().
- Edit all remaining device-open type handling:
If you have changed the type of the open-data that is passed
from the user mode to the driver, you need to edit the related
type handling in your Kernel PlugIn code. For example, if you
previously passed
PWDC_DEVICE as the
open-data type, and you now pass
PCI_DEV_ADDR_DESC*
(as recommended in
Step I.2),
and your code was previously developed using the a WinDriver
sample or wizard-generated Kernel PlugIn driver, you would need
to make the following additional changes:
- In
KP_Close,
replace this line —
free(((PWDC_DEVICE)pDrvContext)->pAddrDesc);
— with the following, to free the correct type:
if (((PCI_DEV_ADDR_DESC *)pDrvContext)->pAddrDesc)
free(((PCI_DEV_ADDR_DESC *)pDrvContext)->pAddrDesc);
- In
KP_IntAtIrql,
replace this line —
PWDC_DEVICE pDev = (PWDC_DEVICE)pIntContext;
— with the following:
PCI_DEV_ADDR_DESC *pDevAddrDesc = (PCI_DEV_ADDR_DESC *)pIntContext;
and edit any remaining
pDev instances in
the function; for example, replace this line —
pAddrDesc = &pDev->pAddrDesc[INTCSR_ADDR_SPACE];
— with the following:
pAddrDesc = &pDevAddrDesc->pAddrDesc[INTCSR_ADDR_SPACE];
|