From - Tue Sep 16 14:10:28 1997 Path: news.mitre.org!blanket.mitre.org!news.tufts.edu!cam-news-feed5.bbnplanet.com!cam-news-hub1.bbnplanet.com!su-news-hub1.bbnplanet.com!news.bbnplanet.com!iagnet.net!vixen.cso.uiuc.edu!howland.erols.net!newsfeed.direct.ca!News1.Vancouver.iSTAR.net!news.istar.net!hammer.uoregon.edu!netnews.nwnet.net!news.microsoft.com!news From: "Paul Sanders" Newsgroups: comp.os.ms-windows.programmer.nt.kernel-mode Subject: Re: DeviceIoControl() and User's Input Buffer Date: 16 Sep 1997 16:04:32 GMT Organization: Microsoft Lines: 279 Message-ID: <01bcc2b9$cf625e80$8fa8369d@paulsan90> References: <341dc205.636240409@news.connectnet.com> NNTP-Posting-Host: 157.54.168.143 X-Newsreader: Microsoft Internet News 4.70.1157 I haven't posted this for a while, so...... Here is an explanation of buffers and DeviceIoControl. First, here are the parameters, BOOL DeviceIoControl( HANDLE hDevice, // handle to device of interest DWORD dwIoControlCode, // control code of operation to perform LPVOID lpInBuffer, // pointer to buffer to supply input data DWORD nInBufferSize, // size of input buffer LPVOID lpOutBuffer, // pointer to buffer to receive output data DWORD nOutBufferSize, // size of output buffer LPDWORD lpBytesReturned, // pointer to variable to receive output byte count LPOVERLAPPED lpOverlapped // pointer to overlapped structure for asynchronous operation ); METHOD_BUFFERED user-mode perspective lpInBuffer - optional, contains data that is written to the driver lpOutBuffer - optional, contains data that is read from the driver after the call has completed lpInBuffer and lpOutBuffer can be two buffers or a single shared buffer. If a shared buffer, lpInBuffer is overwritten by lpOutBuffer. I/O Manager perspective examines nInBufferSize and nOutBufferSize. Allocates memory from non-paged pool and puts the address of this pool in Irp->AssociatedIrp.SystemBuffer. The size of this buffer is equal to the size of the larger of the two bufferes. This buffer is accessible at any IRQL. copies nInBufferSize to irpSp->Parameters.DeviceIoControl.InputBufferLength copies nOutBufferSize to irpSp->Parameters.DeviceIoControl.OutputBufferLength copies contents of lpInBuffer to SystemBuffer allocated above calls your driver Device Driver perspective you have one buffer, Irp->AssociatedIrp.SystemBuffer. You read input data from this buffer and you write output data to the same buffer, overwriting the input data. Before calling IoCompleteRequest, you must - set IoStatus.Status to an approriate NtStatus - if IoStatus.Status == STATUS_SUCCESS set IoStatus.Information to the number of bytes you want copied from the SystemBuffer back into lpOutBuffer. I/O Manager Completion Routine perspective looks at IoStatus block, if IoStatus.Status = STATUS_SUCCESS, copies the number of bytes specified by IoStatus.Information from Irp->AssociatedIrp.SystemBuffer into lpOutBuffer completes the request METHOD_IN_DIRECT user-mode perspective lpInBuffer - optional, contains data that is written to the driver. This buffer is used in the exact same fashion as METHOD_BUFFERED. To avoid confusion, mentally rename this buffer to lpControlBuffer. This is typically a small, optional buffer that might contain a control structure with useful information for the device driver. This buffer is smal and is double buffered. lpOutBuffer - NOT OPTIONAL, This LARGE buffer contains data that is read by the driver. To avoid confusion, mentally rename this buffer to lpDataTransferBuffer. This is physically the same buffer that the device driver will read from. There is no double buffering. Technically, this buffer is still optional, but since you are using this buffering method, what would be the point??? I/O Manager perspective If lpInBuffer exists, allocates memory from non-paged pool and puts the address of this pool in Irp->AssociatedIrp.SystemBuffer. This buffer is accessible at any IRQL. copies nInBufferSize to irpSp->Parameters.DeviceIoControl.InputBufferLength copies nOutBufferSize to irpSp->Parameters.DeviceIoControl.OutputBufferLength copies contents of lpInBuffer to SystemBuffer allocated above So far this is completely identical to METHOD_BUFFERED. Most likely lpInBuffer (mentally renamed to lpControlBuffer) is very small in size. For lpOutBuffer (mentally renamed to lpDataTransferBuffer), an MDL is allocated. lpOutBuffer is probed and locked into memory. Then, the user buffer virtual addresses are checked to be sure they are readable in the caller's access mode. The MDL is address is stored in Irp->MdlAddress. Your driver is called. Device Driver perspective The device driver can read the copy of lpOutBuffer via Irp->AssociatedIrp.SystemBuffer. Anything written by the device driver to this buffer is lost. The I/O Manager does not copy any data back to the user-mode buffers as it did in the completion routine for METHOD_BUFFERED. Art Baker's book is wrong in this respect (page 168, "data going from the driver back to the caller is passed through an intermediate system-space buffer" and page 177, "When the IOCTL IRP is completed, the contents of the system buffer will be copied back into the callers original output buffer". The device driver accesses the Win32 buffer directly via Irp->MdlAddress. The driver uses whatever Mdl API's to read the buffer. Usually, this buffer is to be written to some mass storage media or some similar operation. Since this is a large data transfer, assume a completion routine is required. mark the Irp pending queue it return status pending Device Driver Completion Routine perspective standard completion routine operations set IoStatus.Status to an approriate NtStatus IoStatus.Information is not needed completete the request I/O Manager Completion Routine perspective standard I/O Manager completion routine operations unmap the pages deallocate the Mdl complete the request METHOD_OUT_DIRECT user-mode perspective lpInBuffer - optional, contains data that is written to the driver. This buffer is used in the exact same fashion as METHOD_BUFFERED. To avoid confusion, mentally rename this buffer to lpControlBuffer. This is typically a small, optional buffer that might contain a control structure with useful information for the device driver. This buffer is smal and is double buffered. lpOutBuffer - NOT OPTIONAL, This LARGE buffer contains data that is written by the driver and read by the wer-mode application when the request is completed. To avoid confusion, mentally rename this buffer to lpDataTransferBuffer. This is physically the same buffer that the device driver will write to. There is no double buffering. Technically, this buffer is still optional, but since you are using this buffering method, what would be the point??? I/O Manager perspective If lpInBuffer exists, allocates memory from non-paged pool and puts the address of this pool in Irp->AssociatedIrp.SystemBuffer. This buffer is accessible at any IRQL. copies nInBufferSize to irpSp->Parameters.DeviceIoControl.InputBufferLength copies nOutBufferSize to irpSp->Parameters.DeviceIoControl.OutputBufferLength copies contents of lpInBuffer to SystemBuffer allocated above So far this is completely identical to METHOD_BUFFERED. Most likely lpInBuffer (mentally renamed to lpControlBuffer) is very small in size. For lpOutBuffer (mentally renamed to lpDataTransferBuffer), an MDL is allocated. lpOutBuffer is probed and locked into memory. Then the user buffer's addresses are checked to make sure the caller could write to them in the caller's access mode. The MDL is address is stored in Irp->MdlAddress. Your driver is called. Device Driver perspective The device driver can read the copy of lpOutBuffer via Irp->AssociatedIrp.SystemBuffer. Anything written by the device driver to this buffer is lost. The device driver accesses the Win32 buffer directly via Irp->MdlAddress. The driver uses whatever Mdl API's to write data to the buffer. Usually, this buffer is to be read from some mass storage media or some similar operation. Since this is a large data transfer, assume a completion routine is required. mark the Irp pending queue it return status pending Device Driver Completion Routine perspective standard completion routine operations set IoStatus.Status to an approriate NtStatus IoStatus.Information is not needed completete the request I/O Manager Completion Routine perspective standard I/O Manager completion routine operations unmap the pages deallocate the Mdl complete the request METHOD_NEITHER I/O Manager perspective Irp->UserBuffer = lpOutputBuffer; IrpSp->Parameters.DeviceIoControl.Type3InputBuffer = lpInputBuffer; No comments here. Don't use METHOD_DIRECT unless you know what you are doing. Simple rule. If your IOCtl involves no data transfer buffers, then METHOD_NEITHER is the fastest path through the I/O Manager that involves an Irp. Final Comment Don't touch Irp->UserBuffer. This is a bookmark for the I/O Manager. Two major problems can occur. 1 - page fault at high IRQL, or 2 - you write something to Irp->UserBuffer and the I/O Manager overwrites you in its completion routine. File systems access Irp->UserBuffer, but FSD writers know all of the above and know when it is safe to touch Irp->UserBuffer. jvasquez@getntds.com wrote in article <341dc205.636240409@news.connectnet.com>... > The 3rd parameter passed to DeviceIoControl (lpInBuffer) is a Pointer > to a buffer that contains data. In my Device Driver, I can see the > data pointed to by lpInBuffer. However, if the device driver changes > anything in that buffer and returns to the application, the changes > didn't take place. Why? > > I want to return board configuration data to the application. Any > Ideas. > > John Vasquez (San Diego area) > > I'm trying to return configuration info > >