{"id":366,"date":"2008-10-01T16:43:42","date_gmt":"2008-10-01T16:43:42","guid":{"rendered":"https:\/\/driverentry.com.br\/en\/2008\/10\/01\/buffered-direct-or-neither\/"},"modified":"2026-07-29T18:52:02","modified_gmt":"2026-07-29T18:52:02","slug":"buffered-direct-or-neither","status":"publish","type":"post","link":"https:\/\/driverentry.com.br\/en\/2008\/10\/01\/buffered-direct-or-neither\/","title":{"rendered":"Buffered, Direct or Neither"},"content":{"rendered":"<div style=\"text-align: right;\"><a href=\"https:\/\/driverentry.com.br\/2008\/10\/01\/buffered-direct-ou-neither\/\"><img loading=\"lazy\" decoding=\"async\" title=\"Em Portugues\" src=\"https:\/\/driverentry.com.br\/en\/wp-content\/uploads\/2026\/07\/br.gif\" alt=\"\" width=\"21\" height=\"19\" \/><\/a><\/div>\n<p>In the <a href=\"https:\/\/driverentry.com.br\/en\/2008\/09\/11\/a-pinch-of-virtual-memory\/\">last post<\/a> I gave a brief introduction about some points regarding virtual memory that I consider to be the most relevant to driver developers. With that small load of knowledge, it will be simpler to explain the differences between the methods of transferring data between applications and drivers, as well as other issues, such as interrupt servicing, memory mapping and execution context.<\/p>\n<p>If we think in a very simplified way (and I do mean simplified), drivers are basically the modules that extract data from devices and make it available to applications and vice versa. From this point of view, it really does seem that writing drivers is easy. It even looks like a way of doing a <em>memcpy<\/em> from software to hardware. Today we will see a little about the ways a driver can choose to do this data transfer.<\/p>\n<h3>Using a system Buffer<\/h3>\n<p>The first method is the so-called <strong>Buffered I\/O<\/strong>. This method uses a system buffer to transfer data between the application and the driver. When an application calls the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa365747(VS.85).aspx\">WriteFile<\/a> function passing the data to be sent to the driver, the I\/O Manager makes a copy of the application&#8217;s data into a system buffer. <strong>But what is a system buffer?<\/strong> It is an allocation in <em>System Space<\/em> that was made in <em>Kernel-Mode<\/em>, and for that reason, is accessible in any process context. We already talked about this in the <a href=\"https:\/\/driverentry.com.br\/en\/2008\/09\/11\/a-pinch-of-virtual-memory\/\">last post<\/a>.<\/p>\n<div style=\"font-family: Courier New; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;\">\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">BOOL WINAPI WriteFile(<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">  __in         HANDLE hFile,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">  __in         LPCVOID lpBuffer,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">  __in         DWORD nNumberOfBytesToWrite,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">  __out_opt    LPDWORD lpNumberOfBytesWritten,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">  __inout_opt  LPOVERLAPPED lpOverlapped<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">);<\/pre>\n<\/div>\n<p>The I\/O Manager gets the size of the buffer to be allocated from the <strong>nNumberOfBytesToWrite<\/strong> parameter, then performs a non-paged memory allocation and copies the data that is in <em>User Space<\/em> to <em>System Space<\/em>. If you are slipping on the terms <em>System Space<\/em>, <em>User Space<\/em> and types of memory allocation, take a read of <a href=\"https:\/\/driverentry.com.br\/en\/2008\/09\/11\/a-pinch-of-virtual-memory\/\">this post<\/a> so that things become less obscure for you.<\/p>\n<p>In the driver, the pointer to this buffer is obtained from the IRP and its size is obtained from the IRP&#8217;s stack location. <a href=\"https:\/\/driverentry.com.br\/en\/2007\/02\/12\/cool-but-what-is-an-irp\/\">Cool, but what is an IRP?<\/a> Take a look at this mini example below to get an idea, or you can see the example used in this <a href=\"https:\/\/driverentry.com.br\/en\/2007\/06\/18\/we-want-samples\/\">other post<\/a> that also uses the <em>Buffered<\/em> method to send and receive strings from an example driver.<\/p>\n<div style=\"font-family: Courier New; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;\">\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\"><span style=\"color: green;\">\/\/-f--&gt; Handler routine for IRP_MJ_WRITE.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\"><span style=\"color: green;\">\/\/      Example of obtaining the system buffer<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\"><span style=\"color: green;\">\/\/      allocated by the I\/O Manager in the Buffered method<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">NTSTATUS<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">OnDispatchWrite(__in PDEVICE_OBJECT pDeviceObj,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">                __in PIRP           pIrp)<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">{<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    PIO_STACK_LOCATION  pStack;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    PVOID               pBuffer;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    ULONG               ulLength;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/-f--&gt; Gets the current stack location of the IRP<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    pStack = IoGetCurrentIrpStackLocation();<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/-f--&gt; Here we get the pointer to the buffer<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    pBuffer = pIrp->AssociatedIrp.SystemBuffer;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/-f--&gt; Here the size of the buffer<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    ulLength = pStack->Parameters.Write.Length;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    ...<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">}<\/pre>\n<\/div>\n<p>In read operations, the method is very similar, but although in this case the I\/O Manager also makes the allocation in non-paged memory, it does not make any copy into the system buffer. The system buffer is received by the driver also through <strong>pIrp->AssociatedIrp.SystemBuffer<\/strong>, but its size is obtained from <strong>pStack->Parameters.Read.Length<\/strong>. The driver will fill the buffer with the data coming from the device, and the I\/O Manager will copy the buffer from <em>System Space<\/em> to <em>User Space<\/em> when the IRP is completed, filling the application&#8217;s buffer.<\/p>\n<p><strong>Whoa, whoa! As far as I know, drivers normally complete IRPs in an arbitrary context, which means <em>&#8220;only God knows in which process context&#8221;<\/em>. It is fine if the driver writes to a system buffer, which is valid for any process, but the application&#8217;s buffer is in <em>User Space<\/em> and is only accessible in the context of its own process. How would the I\/O Manager copy the system buffer to the application buffer in an arbitrary context?<\/strong> Wow, that really was an excellent question. I do not think even I would have imagined such a good question. IRPs can be handled both synchronously and asynchronously. The I\/O Manager knows how the IRP was processed, and in the synchronous case, the I\/O Manager is already in the context of the process that made the request, and in this case it has access to both buffers, since the I\/O Manager runs in <em>Kernel-Mode<\/em>. When the IRP is handled asynchronously, the I\/O Manager queues an <strong>APC<\/strong> (<a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms681951.aspx\">Asynchronous Procedure Call<\/a>), which is an asynchronous call executed in the context of a given thread. That thread is precisely the thread that started the operation, and which therefore will be in the right process context to access the application&#8217;s <em>User Space<\/em>.<\/p>\n<div style=\"font-family: Courier New; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;\">\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">BOOL WINAPI ReadFile(<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">  __in         HANDLE hFile,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">  __out        LPVOID lpBuffer,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">  __in         DWORD nNumberOfBytesToRead,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">  __out_opt    LPDWORD lpNumberOfBytesRead,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">  __inout_opt  LPOVERLAPPED lpOverlapped<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">);<\/pre>\n<\/div>\n<p>In the call to the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa365467(VS.85).aspx\">ReadFile<\/a> function, the <em>nNumberOfBytesToRead<\/em> parameter indicates the size of the buffer that the application is offering to the driver. The driver receives this value as the maximum number of bytes that can be returned to the application. Assuming the application has offered 1000 bytes, the I\/O Manager allocates 1000 bytes and passes the buffer to the driver. Let us suppose the driver has only 500 bytes to return to the application; in this case, the I\/O Manager will have to copy to the application buffer only 500 of the 1000 allocated bytes. The I\/O Manager receives this value through the <strong>pIrp->IoStatus.Information<\/strong> field, which is filled in by the driver before the IRP is completed. This way, the I\/O Manager copies only the valid bytes from the system buffer to the application buffer. This same value is returned to the application through the <em>lpNumberOfBytesRead<\/em> parameter.<\/p>\n<p>Using non-paged memory to hold the system buffer assures us that the pages will not be removed from RAM by paging. This allows the page to be accessed even from threads running at a high priority level. However, the <em>Buffered<\/em> method is indicated only for small data movements. Imagine that an application wants to write 10 MB all at once. The I\/O Manager would have to make a <em>System Space<\/em> allocation of 10 MB of non-paged memory, which would not be at all appropriate, since non-paged memory is a scarce resource. If the I\/O Manager manages to make the allocation, it will still have to make a 10 MB copy from the application buffer to the system buffer. This would even work, but we would have serious performance problems. In this case, the most appropriate thing would be to use the method seen next.<\/p>\n<h3>Locking the Application&#8217;s memory<\/h3>\n<p>In the method called <strong>Direct I\/O<\/strong>, as the name already suggests, the driver accesses the application&#8217;s memory pages directly without using an intermediate buffer. This way, the I\/O Manager does not make an allocation in non-paged memory and also does not have to do the BPL-BPC (<em>Buffer over there &#8211; Buffer over here<\/em>). Instead, the I\/O Manager tests the memory pages that make up the buffer offered by the application, creates an <strong>MDL<\/strong> and locks the memory pages in RAM. <strong>Whoa! Hold on there my friend, let us go slowly!<\/strong><\/p>\n<ul>\n<li><strong>Tests the memory pages<\/strong> &#8211; Nothing stops a programmer from doing something silly. An invalid buffer may be passed to the I\/O Manager. It could be that the buffer was not allocated, or that the buffer is smaller than the value indicated in the call to the <em>ReadFile<\/em> or <em>WriteFile<\/em> functions; it could also be that the memory pages offered to <em>ReadFile<\/em> are protected against writing, or that some of the pages used by the buffer have been paged out to disk. If a driver tries to access an invalid or protected page, an exception is generated and a blue screen will emerge from the darkness. <strong>But how is the I\/O Manager going to test the memory?<\/strong> If the buffer is passed as a parameter to the <em>ReadFile<\/em> function, then the driver will perform writes to this buffer. To save time, the I\/O Manager will write one byte to each RAM page just to test access to them. This write is done under an exception handler. If the buffer is invalid or protected, the exception handler will handle it and return an error to the application. If the buffer is passed to the <em>WriteFile<\/em> function, then the buffer will be read by the driver, and in this case, the test would be reading one byte from each page.<\/li>\n<p><br class=\"spacer_\" \/><\/p>\n<li><strong>Creates an MDL<\/strong> &#8211; An MDL (<a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa491609.aspx\">Memory Descriptor List<\/a>) is a data structure that describes the various memory pages that make up a buffer. These pages are the same physical pages used by the application, that is, when the driver writes to these pages, it will already be writing directly to the application&#8217;s buffer. So the I\/O Manager will not need to do any BPL-BPC.<\/li>\n<p><br class=\"spacer_\" \/><\/p>\n<li><strong>Locks the pages in RAM<\/strong> &#8211; This step makes the memory pages that compose the application&#8217;s buffer become non-pageable. This way, they can be accessed by the driver in threads that are running at a high priority level.<\/li>\n<\/ul>\n<p>After all this ritual, the driver now receives the buffer through <strong>pIrp->MdlAddress<\/strong>, but what we will have here is a pointer to an MDL. <strong>But what do I do with an MDL?<\/strong> Most of the time, you will pass it as an argument to a service offered by another driver or system component. Some examples are DMA (<a href=\"http:\/\/en.wikipedia.org\/wiki\/Direct_memory_access\">Direct Memory Access<\/a>) drivers that use an MDL in the call to the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms806324.aspx\">MapTransfer<\/a> function, or even when an MDL is passed on to USB (<a href=\"http:\/\/en.wikipedia.org\/wiki\/USB\">Universal Serial Bus<\/a>) controller routines, such as <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms790516.aspx\">UsbBuildInterruptOrBulkTransferRequest<\/a>. MDLs are opaque structures, but if you want to have access to the application&#8217;s buffer, then we must call the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms802005.aspx\">MmGetSystemAddressForMdlSafe<\/a> function to get the address of the buffer to be written\/read. Note that the address returned by this function is in <em>System Space<\/em>, and thus, accessible in any process context. <strong>But is not the application buffer in <em>User Space<\/em>?<\/strong> Yes, but what we have here is a physical memory page being mapped both to the application&#8217;s address space and to the system address space.<\/p>\n<p>The size of the buffer described by the MDL is also obtained from the IRP&#8217;s stack location, just as in the <em>Buffered<\/em> method.<\/p>\n<h3>Neither Buffered I\/O nor Direct I\/O<\/h3>\n<p>The third method is simply not using the first two. In the method called <strong>Neither<\/strong>, the I\/O Manager does not make a copy into a system buffer nor build an MDL to describe the application&#8217;s buffer. When the IRP reaches your driver, you have access to the virtual address of the buffer offered by the application through <strong>pIrp->UserBuffer<\/strong>. This address points to <em>User Space<\/em>, and for that reason, remember that this address is only valid in the context of the process that requested the I\/O. The use of this method requires more care, because your driver needs to be the first driver in the device stack, and thus, ensure that the IRP reaches your driver in the context of the process that made the I\/O request.<\/p>\n<p>You can check whether you are in the context of the process that requested the operation by doing the test below.<\/p>\n<div style=\"font-family: Courier New; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;\">\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\"><span style=\"color: green;\">\/****<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\"><span style=\"color: green;\">***     EstouNoContextoDoProcessoQueGerouEssaIrp<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\"><span style=\"color: green;\">**<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\"><span style=\"color: green;\">**      Function with a ridiculous name that checks whether<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\"><span style=\"color: green;\">**      we are in the context of the process that generated<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\"><span style=\"color: green;\">**      the IRP passed as a parameter.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\"><span style=\"color: green;\">*\/<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">BOOLEAN EstouNoContextoDoProcessoQueGerouEssaIrp(__in PIRP pIrp)<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">{<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    PETHREAD    pEThread;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    PEPROCESS   pEProcess;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/-f--&gt; Gets the thread that generated the IRP<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    pEThread = pIrp->Tail.Overlay.Thread;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/-f--&gt; Gets the process the thread belongs to<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    pEProcess = IoThreadToProcess(pEThread);<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/-f--&gt; Here we compare the current process with<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/      the process that generated the IRP<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: blue;\">return<\/span> (PsGetCurrentProcess() == pEProcess);<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">}<\/pre>\n<\/div>\n<p>The fact of being in the correct process context does not guarantee that the buffer passed as a parameter is valid. Unlike the <em>Direct<\/em> method, at this point the I\/O Manager did not test the buffer before passing the IRP to the driver. We will have to do this ourselves. Remember that, just as in <em>User-Mode<\/em>, when accessing an invalid buffer the driver will receive an exception that must be handled, otherwise, all blue.<\/p>\n<p>To perform the test, we will have to access one byte of each page of the buffer that was passed to us and check whether the world ends. The <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa489870.aspx\">ProbeForRead<\/a> and <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms797108.aspx\">ProbeForWrite<\/a> routines do this for us, but they must be called inside an exception handler. It is worth remembering that in a read operation, the application sends us a buffer where the driver will write data for the application. Since the driver will perform a write to this buffer, we will have to perform a write test (<em>ProbeForWrite<\/em>) in read operations (<em>ReadFile<\/em>). Analogously, the driver must perform a read test (<em>ProbeForRead<\/em>) in write operations (<em>WriteFile<\/em>). Take a look at the example read routine that follows below. As you should already be used to, read the comments that complement the text.<\/p>\n<div style=\"font-family: Courier New; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;\">\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\"><span style=\"color: green;\">\/****<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\"><span style=\"color: green;\">***     OnDispatchRead<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\"><span style=\"color: green;\">**<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\"><span style=\"color: green;\">**      Another function with a silly little example name.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\"><span style=\"color: green;\">**      Validates the buffer sent by the application through<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\"><span style=\"color: green;\">**      the Neither method and writes a numeric sequence<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\"><span style=\"color: green;\">**      into the application's buffer.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\"><span style=\"color: green;\">*\/<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">NTSTATUS OnDispatchRead(__in PDEVICE_OBJECT pDeviceObj,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">                        __in PIRP           pIrp)<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">{<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    PIO_STACK_LOCATION  pStack;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    PVOID               pBuffer;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    ULONG               ulLength;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/-f--&gt; Checks whether we are in the context of the process<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/      that generated this IRP<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: blue;\">if<\/span> (!EstouNoContextoDoProcessoQueGerouEssaIrp(pIrp))<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    {<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        <span style=\"color: green;\">\/\/-f--&gt; Signals to the I\/O Manager that the house fell down<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        pIrp->IoStatus.Status = STATUS_INVALID_PARAMETER;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        pIrp->IoStatus.Information = <span style=\"color: purple;\">0<\/span>;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        <span style=\"color: green;\">\/\/-f--&gt; Completes the IRP with failure<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        IoCompleteRequest(pIrp, IO_NO_INCREMENT);<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        <span style=\"color: blue;\">return<\/span> STATUS_INVALID_PARAMETER;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    }<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/-f--&gt; Gets the current stack location<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    pStack = IoGetCurrentIrpStackLocation(pIrp);<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/-f--&gt; Here we get the address of the buffer offered<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/      by the application as well as its size.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/      Note that this buffer must be in User Space<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    pBuffer = pIrp->UserBuffer;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    ulLength = pStack->Parameters.Read.Length;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/-f--&gt; The functions that test the buffer throw exceptions<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/      if the buffer is invalid. That is why we have<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/      to do the test inside an exception handler<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: blue;\">__try<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    {<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        <span style=\"color: green;\">\/\/-f--&gt; If you take a look at the reference, you will see that<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        <span style=\"color: green;\">\/\/      this routine returns VOID, so the only<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        <span style=\"color: green;\">\/\/      way to know whether the buffer is invalid is<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        <span style=\"color: green;\">\/\/      by handling the exception that will be generated.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        ProbeForWrite(pBuffer,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">                      ulLength,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">                      <span style=\"color: purple;\">1<\/span>);<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    }<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: blue;\">__except<\/span>(EXCEPTION_EXECUTE_HANDLER)<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    {<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        NTSTATUS    nts;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        <span style=\"color: green;\">\/\/-f--&gt; Oops! Invalid buffer.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        <span style=\"color: green;\">\/\/      Let us get the exception code and put an<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        <span style=\"color: green;\">\/\/      end to this suffering<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        nts = GetExceptionCode();<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        pIrp->IoStatus.Status = nts;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        pIrp->IoStatus.Information = <span style=\"color: purple;\">0<\/span>;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        IoCompleteRequest(pIrp, IO_NO_INCREMENT);<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        <span style=\"color: blue;\">return<\/span> nts;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    }<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/-f--&gt; Here we know the buffer is safe to receive<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/      writes. Let us just write a numeric sequence<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/      just to...<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: blue;\">for<\/span> (ULONG i = <span style=\"color: purple;\">0<\/span>; i < ulLength, i++)<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        ((PUCHAR)pBuffer)[i] = (UCHAR)i;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/-f--&gt; Here we report that the operation was carried out<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/      successfully.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    pIrp->IoStatus.Status = STATUS_SUCCESS;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/-f--&gt; Even though in the Neither method the I\/O Manager does not<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/      use this number to do BPL-BPC, this<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/      number is still returned by the ReadFile function<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/      to tell the application how many bytes of the buffer<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/      are valid for the application to read.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    pIrp->IoStatus.Information = ulLength;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/-f--&gt; Gives the IRP a Fatality<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    IoCompleteRequest(pIrp, IO_NO_INCREMENT);<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: blue;\">return<\/span> STATUS_SUCCESS;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">}<\/pre>\n<\/div>\n<p>For all the methods, it is important to note that setting the <strong>pIrp->IoStatus.Information<\/strong> field tells the application how many bytes were read or written in the buffer, regardless of whether or not there is a system buffer copy as in the case of the <em>Buffered<\/em> method.<\/p>\n<p>Another thing that will not change for the different methods is obtaining the size of the buffer offered by the application. This value always comes through the stack location, as already seen in the methods already discussed.<\/p>\n<h3>How to select the method<\/h3>\n<p>It makes total sense for the choice of method to be made before the first IRP reaches the driver. This is done right after the device is created. After the call to the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa490468.aspx\">IoCreateDevice <\/a> function finishes, we receive the new device through an output pointer. The <strong>Flags<\/strong> member of the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa491677.aspx\">DEVICE_OBJECT<\/a> structure is a bit mask and the <strong>DO_BUFFERED_IO<\/strong> and <strong>DO_DIRECT_IO<\/strong> bits configure the transfer method.<\/p>\n<p>So it is that easy. To configure the <em>Buffered<\/em> method, we set the DO_BUFFERED_IO bit; to configure the <em>Direct<\/em> method, we set the DO_DIRECT_IO bit; and finally to set the <em>Neither<\/em> method, we do not set either of these bits. I have read in some book, which I cannot find now, that the behavior is undefined if you set both bits.<\/p>\n<p>Here is another silly little example of how to set the device that has just been created for transfers in the <em>Buffered<\/em> method.<\/p>\n<div style=\"font-family: Courier New; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;\">\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/-f--&gt; Creates the device that will receive the IRPs<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    nts = IoCreateDevice(pDriverObj,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">                         <span style=\"color: purple;\">0<\/span>,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">                         &amp;usDeviceName,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">                         FILE_DEVICE_UNKNOWN,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">                         <span style=\"color: purple;\">0<\/span>,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">                         FALSE,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">                         &amp;pDeviceObj);<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/-f--&gt; Checks whether the device was created<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: blue;\">if<\/span> (!NT_SUCCESS(nts))<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        <span style=\"color: blue;\">return<\/span> nts;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/-f--&gt; Here we can already configure the desired<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/      transfer method, which in this<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/      example is Buffered I\/O<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    pDeviceObj->Flags |= DO_BUFFERED_IO;<\/pre>\n<\/div>\n<p><strong>But what if an IRP is delivered to the driver before we set these bits?<\/strong> Another excellent question. Things happen like this. Whenever a new device is created, the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms790739.aspx\">DO_DEVICE_INITIALIZING<\/a> bit is set. IRPs only start being delivered to this device when the driver clears this bit. This allows us to initialize the device before any IRP arrives.<\/p>\n<p><strong>Nice try, smart guy, but <a href=\"https:\/\/driverentry.com.br\/en\/2007\/06\/18\/we-want-samples\/\">your example<\/a> does not clear this bit. How do you explain that?<\/strong> You are impossible today! At the end of the <em>DriverEntry<\/em> routine, when control returns to the I\/O Manager, it scans the list of devices created by the driver and clears this bit for us. It is important to remember that we still need to clear this bit when we create a new device after the <em>DriverEntry<\/em> routine has finished. A very common example is WDM devices, which are created in the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms795509.aspx\">AddDevice<\/a> routine, but that will be for another time. This post has already gotten very long.<\/p>\n<p>See you! \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the last post I gave a brief introduction about some points regarding virtual memory that I consider to be the most relevant to driver developers. With that small load of knowledge, it will be simpler to explain the differences between the methods of transferring data between applications and drivers, as well as other issues, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"pagelayer_contact_templates":[],"_pagelayer_content":"","footnotes":""},"categories":[1],"tags":[],"class_list":["post-366","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/driverentry.com.br\/en\/wp-json\/wp\/v2\/posts\/366","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/driverentry.com.br\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/driverentry.com.br\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/driverentry.com.br\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/driverentry.com.br\/en\/wp-json\/wp\/v2\/comments?post=366"}],"version-history":[{"count":1,"href":"https:\/\/driverentry.com.br\/en\/wp-json\/wp\/v2\/posts\/366\/revisions"}],"predecessor-version":[{"id":367,"href":"https:\/\/driverentry.com.br\/en\/wp-json\/wp\/v2\/posts\/366\/revisions\/367"}],"wp:attachment":[{"href":"https:\/\/driverentry.com.br\/en\/wp-json\/wp\/v2\/media?parent=366"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/driverentry.com.br\/en\/wp-json\/wp\/v2\/categories?post=366"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/driverentry.com.br\/en\/wp-json\/wp\/v2\/tags?post=366"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}