Uploading firmware to device via DMA

Hi. I a thinking of how I can implement a filter/function driver whose job it is to upload 16K bytes of firmware to the device. I can’t use WriteFile from the user application because that is used for standard I/O the device is designed to do. So the user application can open a file handle to the driver and use DeviceIoControl with a custom IOCTL code (e.g., IOCTL_FIRMWARE CTL_CODE(0x8000, 0x800, METHOD_IN_DIRECT, FILE_WRITE_DATA).

In the EvtIoControl(), the driver will DMA the firmware to the PCIe device. The device implements packet DMA for this. The data must be double-word aligned.

After creating the deice object, I will initialize the DMA objects as follows:
WdfDeviceSetAlignmentRequirement(wdfDevice, 3); // DWORD aligned DMA.
WDF_DMA_ENABLER_CONFIG_INIT(&wdfDmaConfig, WdfDmaProfilePacket, 16*1024);
WdfDmaEnablerCreate(wdfDevice, &wdfDmaConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&(pDeviceContext->wdfDmaEnabler));
WdfDmaTransactionCreate(pDeviceContext->wdfDmaEnabler,
WDF_NO_OBJECT_ATTRIBUTES,
&(pDeviceContext->wdfDmaTransaction));

In the EvtIoControl for the queue, the driver will initiate the DMA transaction as follows:
WdfDmaTransactionInitializeUsingRequest(pDeviceContext->wdfDmaTransaction,
wdfRequest,
EvtProgramDma,
WdfDmaDirectionWriteToDevice);

WdfDmaTransactionExecute(pDeviceContext->wdfDmaTransaction,
WDF_NO_CONTEXT);

I am omitting the ISR and DPC code, but you get the idea.

In the user application, the code may look like the following:
BYTE abFirmware[16 * 1024]; // local variable.

DeviceIoControl(hDev, // device to be queried
IOCTL_FIRMWARE , // operation to perform
&abFirmware, sizeof(abFirmware), // input buffer
NULL, 0, // no output buffer
&dwBytes, // # bytes transferred
NULL); // synchronous I/O

The problem I see is that the user application buffer may not be DWORD aligned. Does this mean I should allocate my own 16K buffer in the driver and copy the users data to it and then use the driver’s buffer fro DMA? Can I use the buffered IO method to have the framework do the copy for me? I probably need to check for valid buffers in the driver. Any thoughts on good practices for this situation will be much appreciated.

Thanks!

xxxxx@bellsouth.net wrote:

Hi. I a thinking of how I can implement a filter/function driver whose job it is to upload 16K bytes of firmware to the device. I can’t use WriteFile from the user application because that is used for standard I/O the device is designed to do. So the user application can open a file handle to the driver and use DeviceIoControl with a custom IOCTL code (e.g., IOCTL_FIRMWARE CTL_CODE(0x8000, 0x800, METHOD_IN_DIRECT, FILE_WRITE_DATA).

In the user application, the code may look like the following:
BYTE abFirmware[16 * 1024]; // local variable.

DeviceIoControl(hDev, // device to be queried
IOCTL_FIRMWARE , // operation to perform
&abFirmware, sizeof(abFirmware), // input buffer
NULL, 0, // no output buffer
&dwBytes, // # bytes transferred
NULL); // synchronous I/O

The problem I see is that the user application buffer may not be DWORD aligned. Does this mean I should allocate my own 16K buffer in the driver and copy the users data to it and then use the driver’s buffer fro DMA? Can I use the buffered IO method to have the framework do the copy for me?

Perhaps I missed it, but I don’t think there is any contract that
guarantees alignment for a METHOD_BUFFERED buffer.

You really have two choices: either allocate your own buffer and copy,
or put the burden on the application to give you an aligned buffer, and
return STATUS_DATATYPE_MISALIGNMENT if he violates that rule. For
METHOD_IN_DIRECT, the buffer you get will have the exact same alignment
as the user’s buffer.

I probably need to check for valid buffers in the driver.

I’m not sure what that means. You certainly need to verify the LENGTH
of the buffer, but I/O manager guarantees that the buffer you get is
valid for whatever length it told you.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

What about failing the firmware operation if the client doesn’t DWORD align the buffer they give you? That keeps your driver code much simpler, and it’s not particularly onerous for the client.

You could use method buffered, in which case your buffer will have the same alignment as pool allocations. For an infrequent 16KB operation that seems fine too. And it will make your DMA path simpler than trying to copy the buffer only if it’s not properly aligned.

-p

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@bellsouth.net
Sent: Tuesday, March 25, 2014 10:14 AM
To: Windows System Software Devs Interest List
Subject: [ntdev] Uploading firmware to device via DMA

Hi. I a thinking of how I can implement a filter/function driver whose job it is to upload 16K bytes of firmware to the device. I can’t use WriteFile from the user application because that is used for standard I/O the device is designed to do. So the user application can open a file handle to the driver and use DeviceIoControl with a custom IOCTL code (e.g., IOCTL_FIRMWARE CTL_CODE(0x8000, 0x800, METHOD_IN_DIRECT, FILE_WRITE_DATA).

In the EvtIoControl(), the driver will DMA the firmware to the PCIe device. The device implements packet DMA for this. The data must be double-word aligned.

After creating the deice object, I will initialize the DMA objects as follows:
WdfDeviceSetAlignmentRequirement(wdfDevice, 3); // DWORD aligned DMA.
WDF_DMA_ENABLER_CONFIG_INIT(&wdfDmaConfig, WdfDmaProfilePacket, 16*1024); WdfDmaEnablerCreate(wdfDevice, &wdfDmaConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&(pDeviceContext->wdfDmaEnabler));
WdfDmaTransactionCreate(pDeviceContext->wdfDmaEnabler,
WDF_NO_OBJECT_ATTRIBUTES,
&(pDeviceContext->wdfDmaTransaction));

In the EvtIoControl for the queue, the driver will initiate the DMA transaction as follows:
WdfDmaTransactionInitializeUsingRequest(pDeviceContext->wdfDmaTransaction,
wdfRequest,
EvtProgramDma,
WdfDmaDirectionWriteToDevice);

WdfDmaTransactionExecute(pDeviceContext->wdfDmaTransaction,
WDF_NO_CONTEXT);

I am omitting the ISR and DPC code, but you get the idea.

In the user application, the code may look like the following:
BYTE abFirmware[16 * 1024]; // local variable.

DeviceIoControl(hDev, // device to be queried
IOCTL_FIRMWARE , // operation to perform
&abFirmware, sizeof(abFirmware), // input buffer
NULL, 0, // no output buffer
&dwBytes, // # bytes transferred
NULL); // synchronous I/O

The problem I see is that the user application buffer may not be DWORD aligned. Does this mean I should allocate my own 16K buffer in the driver and copy the users data to it and then use the driver’s buffer fro DMA? Can I use the buffered IO method to have the framework do the copy for me? I probably need to check for valid buffers in the driver. Any thoughts on good practices for this situation will be much appreciated.

Thanks!


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Follow-up question to help me understand buffers and IOCTL.

I have created a custom IOCTL code as follows:
#define IOCTL_FIRMWARE CTL_CODE(0x8000, 0x800, METHOD_IN_DIRECT, FILE_WRITE_DATA)

I am expecting to send data from the user application to the driver which will program the PCI device bus master registers for sending the data to the device.

I create the DMA enabler and transaction objects after creating the device object.

In the EvtIoControl callback for the driver’s queue (sequential), I call WdfDmaTransactionInitializeUsingRequest(pDeviceContext->wdfDmaTransaction,
wdfRequest,
EvtProgramDma,
WdfDmaDirectionWriteToDevice);

This calls fails with a STATUS_BUFFER_TOO_SMALL if the user application does not specify an output buffer in the DeviceIoControl call. It succeeds when the user application supplies an output buffer in the DeviceIoControl. The output buffer should not be needed because we are writing from the user-mode application to the driver to the device. Any ideas as to what may be happening? Did is miss setting a direction somewhere else?

What does !wdfkd.wdflogdump say?

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@bellsouth.net
Sent: Tuesday, March 25, 2014 1:04 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Uploading firmware to device via DMA

Follow-up question to help me understand buffers and IOCTL.

I have created a custom IOCTL code as follows:
#define IOCTL_FIRMWARE CTL_CODE(0x8000, 0x800, METHOD_IN_DIRECT, FILE_WRITE_DATA)

I am expecting to send data from the user application to the driver which will program the PCI device bus master registers for sending the data to the device.

I create the DMA enabler and transaction objects after creating the device object.

In the EvtIoControl callback for the driver’s queue (sequential), I call WdfDmaTransactionInitializeUsingRequest(pDeviceContext->wdfDmaTransaction,
wdfRequest,
EvtProgramDma,
WdfDmaDirectionWriteToDevice);

This calls fails with a STATUS_BUFFER_TOO_SMALL if the user application does not specify an output buffer in the DeviceIoControl call. It succeeds when the user application supplies an output buffer in the DeviceIoControl. The output buffer should not be needed because we are writing from the user-mode application to the driver to the device. Any ideas as to what may be happening? Did is miss setting a direction somewhere else?


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Hi Doron:

Apparently something is missing in WinDbg that is not letting me access the log (the driver is still loaded).

Here is the trace of commands I have issued (my driver is TrembleDriver.sys):

.load wdfkd.dll

.sympath c:\shared;srv*c:\msftdbs*http://msdl.microsoft.com/download/symbols

c:\shared above is also where I am placing a copy of the trembledriver.sys and
trembledriver.pdb files.

!wdfldr
The command above shows my driver in a list:

LoadedModuleList 0xfffff8800114a2b8

LIBRARY_MODULE 0xfffffa8006c74130
Version v1.11
Service \Registry\Machine\System\CurrentControlSet\Services\Wdf01000
ImageName Wdf01000.sys
ImageAddress 0xfffff8800107f000
ImageSize 0xc2000
Associated Clients: 9

ImageName Ver WdfGlobals FxGlobals ImageAddress ImageSize
TrembleDriver.sys v0.0 0xfffffa8007b838c0 0xfffffa8007b83740 0xfffff8800489d000 0x0000c000
peauth.sys v0.0 0xfffffa800772b190 0xfffffa800772b010 0xfffff880046d7000 0x000a6000
monitor.sys v0.0 0xfffffa8006cc2dd0 0xfffffa8006cc2c50 0xfffff88003715000 0x0000e000
umbus.sys v0.0 0xfffffa80073a8190 0xfffffa80073a8010 0xfffff880033d6000 0x00012000
CompositeBus.sys v0.0 0xfffffa8007398fc0 0xfffffa8007398e40 0xfffff88003380000 0x00010000
intelppm.sys v0.0 0xfffffa80073754a0 0xfffffa8007375320 0xfffff8800336a000 0x00016000
vmstorfl.sys v0.0 0xfffffa800708caf0 0xfffffa800708c970 0xfffff880018b4000 0x00010000
vdrvroot.sys v0.0 0xfffffa8006f29910 0xfffffa8006f29790 0xfffff880011ee000 0x0000d000
msisadrv.sys v0.0 0xfffffa8006f04310 0xfffffa8006f04190 0xfffff880011b1000 0x0000a000

Total: 1 library loaded

!wdflogdump trembledriver

The command above shows the following output:

Trace searchpath is:

Trace format prefix is: %7!u!: %!FUNC! -
Trying to extract TMF information from - c:\shared\Wdf01000.pdb\FABEC58794454D0D9B539B58E2D0A0922\Wdf01000.pdb
Log at fffffa8006cfddf0
Gather log: Please wait, this may take a moment (reading 68635 bytes).
% read so far …
warn: The log could not be accessed
hint: Are the symbols the WDF library available?
hint: The log is inaccessable after driver unload.

What else do I need to do in order to make the log visible to WinDbg? Thanks!

On 25-Mar-2014 22:03, xxxxx@bellsouth.net wrote:

This calls fails with a STATUS_BUFFER_TOO_SMALL if the user application does not specify an output buffer in the DeviceIoControl call.
> It succeeds when the user application supplies an output buffer in
the DeviceIoControl. The output buffer should not be needed because we
are writing from the user-mode application to the driver to the device.
Any ideas as to what may be happening? Did is miss setting a
direction somewhere else?

Ok then indeed you can use some help understanding the ioctls buffers.
The 2nd buffer of DeviceIoControl(), named “output” in the MSDN
documentation, can be either input or output, depending on
METHOD_IN_DIRECT or METHOD_OUT_DIRECT in the ioctl code.
In your case, the 2nd buffer is “input” too: yes, both buffers are input.
Read once again the WDK documentation, and hopefully you will understand.
– pp

The DeviceIoControl call is, as discussed below, badly specified and
poorly documented. I introduce it in my course by saying “The input
buffer is output, and the output buffer is input, except when the output
buffer is output”. That pretty much sums up what can happen without adult
supervision.

I actually found a Microsoft document that referred to the first argument
as the “parameters” buffer and the second argument as the “data” buffer.
This makes far more sense, but the horrible naming is so ingrained in the
culture now that it may never be corrected, and you are just the most
recent of its victims. There will be many others that follow you.
joe

On 25-Mar-2014 22:03, xxxxx@bellsouth.net wrote:
>
> This calls fails with a STATUS_BUFFER_TOO_SMALL if the user application
> does not specify an output buffer in the DeviceIoControl call.
> It succeeds when the user application supplies an output buffer in
the DeviceIoControl. The output buffer should not be needed because we
are writing from the user-mode application to the driver to the device.
Any ideas as to what may be happening? Did is miss setting a
direction somewhere else?

Ok then indeed you can use some help understanding the ioctls buffers.
The 2nd buffer of DeviceIoControl(), named “output” in the MSDN
documentation, can be either input or output, depending on
METHOD_IN_DIRECT or METHOD_OUT_DIRECT in the ioctl code.
In your case, the 2nd buffer is “input” too: yes, both buffers are input.
Read once again the WDK documentation, and hopefully you will understand.
– pp


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

Pavel A and Joseph M. Newcomer:

After reading and re-reading the WDK docs and re-reading (with a nap in between ;-)), I also reached the conclusion that I will need to specify both buffers. However, my reading didn’t enlighten me why I would need to do so. Your posts have made it much clearer. Thanks!

The DeviceIoControl documentation isn’t simply misleading it appears to be flat out wrong in http://msdn.microsoft.com/en-us/library/windows/desktop/aa363216(v=vs.85).aspx

The documentation says about lpOutBuffer: “This parameter can be NULL if dwIoControlCode specifies an operation that does not return data.” This appears to be completely incorrect.

The documentation on “Buffer Descriptions for I/O Control Codes” at http://msdn.microsoft.com/en-us/library/windows/hardware/ff540663(v=vs.85).aspx does a much better job describing the buffers. According to this doc:

  1. “Input” buffer is in Irp->AssociatedIrp.SystemBuffer, and
  2. “Output” buffer is in Irp->MdlAddress.
    However, if METHOD_IN_DIRECT is specified then the “output” buffer is also to be considered an input buffer. This matches what Pavel stated in his post.

So Joseph, it seems to me that the “input buffer is always input but the output buffer can be either output or input”. Please correct me if I am still missing something.

Going back to my implementation, it seems I should continue to use METHOD_IN_DIRECT and use the “output” buffer (data buffer as Joseph suggests) as the firmware input that is sent to the device and I should simply set the “input” buffer to NULL because it serves no purpose. Initial testing indicates that the WdfDmaTransactionInitializeUsingRequest() function is now completing correctly as opposed to returning STATUS_BUFFER_TOO_SMALL.

You can easily and correctly send an ioctl request that doesn’t have an output buffer. The output buffer requirement is within WdfDmaTransactionInitializeUsingRequest

d

Bent from my phone


From: xxxxx@bellsouth.netmailto:xxxxx
Sent: ?3/?25/?2014 7:40 PM
To: Windows System Software Devs Interest Listmailto:xxxxx
Subject: RE:[ntdev] Uploading firmware to device via DMA

Pavel A and Joseph M. Newcomer:

After reading and re-reading the WDK docs and re-reading (with a nap in between ;-)), I also reached the conclusion that I will need to specify both buffers. However, my reading didn’t enlighten me why I would need to do so. Your posts have made it much clearer. Thanks!

The DeviceIoControl documentation isn’t simply misleading it appears to be flat out wrong in http://msdn.microsoft.com/en-us/library/windows/desktop/aa363216(v=vs.85).aspx

The documentation says about lpOutBuffer: “This parameter can be NULL if dwIoControlCode specifies an operation that does not return data.” This appears to be completely incorrect.

The documentation on “Buffer Descriptions for I/O Control Codes” at http://msdn.microsoft.com/en-us/library/windows/hardware/ff540663(v=vs.85).aspx does a much better job describing the buffers. According to this doc:
1. “Input” buffer is in Irp->AssociatedIrp.SystemBuffer, and
2. “Output” buffer is in Irp->MdlAddress.
However, if METHOD_IN_DIRECT is specified then the “output” buffer is also to be considered an input buffer. This matches what Pavel stated in his post.

So Joseph, it seems to me that the “input buffer is always input but the output buffer can be either output or input”. Please correct me if I am still missing something.

Going back to my implementation, it seems I should continue to use METHOD_IN_DIRECT and use the “output” buffer (data buffer as Joseph suggests) as the firmware input that is sent to the device and I should simply set the “input” buffer to NULL because it serves no purpose. Initial testing indicates that the WdfDmaTransactionInitializeUsingRequest() function is now completing correctly as opposed to returning STATUS_BUFFER_TOO_SMALL.


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer</mailto:xxxxx></mailto:xxxxx>

Doron:

You can easily and correctly send an ioctl request that doesn’t have an output
buffer. The output buffer requirement is within
WdfDmaTransactionInitializeUsingRequest

On further reflection, I agree with you. I suppose I could write my own DMA transaction object initialization routine that used the appropriate buffer. After the initialization completes, the framework should be able to split the transaction into transfers as normal.

xxxxx@bellsouth.net wrote:

Follow-up question to help me understand buffers and IOCTL.

I have created a custom IOCTL code as follows:
#define IOCTL_FIRMWARE CTL_CODE(0x8000, 0x800, METHOD_IN_DIRECT, FILE_WRITE_DATA)

I am expecting to send data from the user application to the driver which will program the PCI device bus master registers for sending the data to the device.

I create the DMA enabler and transaction objects after creating the device object.

In the EvtIoControl callback for the driver’s queue (sequential), I call WdfDmaTransactionInitializeUsingRequest(pDeviceContext->wdfDmaTransaction,
wdfRequest,
EvtProgramDma,
WdfDmaDirectionWriteToDevice);

This calls fails with a STATUS_BUFFER_TOO_SMALL if the user application does not specify an output buffer in the DeviceIoControl call. It succeeds when the user application supplies an output buffer in the DeviceIoControl. The output buffer should not be needed because we are writing from the user-mode application to the driver to the device. Any ideas as to what may be happening? Did is miss setting a direction somewhere else?

It is easy to get turned around with the terms “input buffer” and
“output buffer” in Windows ioctls, because that doesn’t accurately
describe how they are used. I have started using “first buffer” and
“second buffer” in most cases.

With BUFFERED, IN_DIRECT and OUT_DIRECT ioctls, the first buffer
(colloquially called the “input buffer”) is always buffered. The driver
deals with a copy. With BUFFERED, the second buffer (colloquially
called the “output buffer”) is also copied. With IN_DIRECT and
OUT_DIRECT, the second buffer is the one that gets directly mapped. The
DMA mechanism will always use the second/output buffer for its mapping,
no matter what direction the DMA is going.

So, for an IN_DIRECT or OUT_DIRECT ioctl, the large buffer ALWAYS needs
to be the second (“output”) buffer.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.