Add new documentation
authorDavid Welch <welch@cwcom.net>
Sun, 17 Jan 1999 17:17:09 +0000 (17:17 +0000)
committerDavid Welch <welch@cwcom.net>
Sun, 17 Jan 1999 17:17:09 +0000 (17:17 +0000)
svn path=/trunk/; revision=174

reactos/doc/DIRS [new file with mode: 0644]
reactos/doc/HACKING [new file with mode: 0644]
reactos/doc/INDEX [new file with mode: 0644]
reactos/doc/INTERNALS [new file with mode: 0644]
reactos/doc/notes [new file with mode: 0644]

diff --git a/reactos/doc/DIRS b/reactos/doc/DIRS
new file mode 100644 (file)
index 0000000..38f0f3e
--- /dev/null
@@ -0,0 +1,22 @@
+DIRECTORIES
+
+system           : compiled versions of the various system components and
+                   libraries
+ntoskrnl         : kernel source
+ntoskrnl/hal     : hardware abstraction layer source
+ntoskrnl/mm      : memory managment subsystem source
+ntoskrnl/io      : IO manager subsystem source
+ntoskrnl/ke      : kernel source
+include          : win32 headers
+include/internal : kernel private header files
+include/ntdll    : system library private header files
+include/kernel32 : system library private header files
+include/ddk      : header files for modules
+lib/ntdll        : NT dll source
+lib/kernel32     : kernel32 source
+doc              : documentation
+loaders/dos      : DOS based loader
+loaders/boot     : boot loader
+services         : various services (device drivers, filesystems etc)
+services/dd      : device drivers
+services/fs      : file systems
diff --git a/reactos/doc/HACKING b/reactos/doc/HACKING
new file mode 100644 (file)
index 0000000..c6bab95
--- /dev/null
@@ -0,0 +1,130 @@
+* Introduction
+
+Having successfully built ReactOS and been amazed by what it does, you're
+now desperate to fill in some of the omissions, this document shows you how.
+
+* Prerequisites
+
+A working knowledge of NT driver development is useful for understanding the
+kernel and some of its abstractions. The NT4 ddk is available for free
+download from http://www.microsoft.com/hwdev/. The Windows 98 and Windows
+2000 DDKs are also available but the NT4 one is the most useful. See
+Legal Stuff below however.
+
+There are a number of books on NT driver development, I would recommend
+'Windows NT Device Driver Development' (http://www.osr.com/book/) since OSR
+seem to know their stuff. There is only one book on NT filesystem
+development 'Windows NT File System Internals'. Please don't buy any of
+these books unless you need to, and can afford it. 
+
+These mailing lists and newsgroups are useful for NT internals related 
+questions,
+           ntfsd@atria.com, ntdev@atria.com 
+                           (subscribe by email to majordomo@atria.com)
+          comp.os.????
+          microsoft.public.????
+          
+* Style
+
+There is no coding style used for ReactOS, however the following guidelines
+make things easier
+
+     Include information at the top of a module about its purpose, contact
+     information for its programmer and any useful notes. 
+     
+     Include a comment by each non-trival function describing its arguments,
+     purpose and any other notes.
+     
+     Update the documentation in this directory
+     
+These guidelines are an ideal, no one manages to implement them all the
+time, straightforward working code is probably just as good.
+
+* Debugging
+
+Debugging kernel-mode code is tricky, these are some snippets
+
+    DbgPrint writes a message to the console using a printf style format
+    string. The DPRINT macro (defined in internal/debug.h) expands to
+    DbgPrint unless NDEBUG is defined, this is useful for having copious
+    output from a module only when a problem is being debugging. DPRINT
+    also prefixes the message with the file and line number to make it
+    easier to see where output is coming from. DbgPrint can be used at any
+    point including in interrupt handlers.
+    
+    There are options in ntoskrnl/hal/x86/printk.c for copying DbgPrint
+    output to a serial device (parallel support should also be added). This
+    can be useful if a lot of output is being generated.
+    
+    It should be possible to include support for debugging the kernel with
+    gdb over a serial line. Bochs (a shareware CPU emulator) is also useful
+    for debugging the kernel, I wrote some patches to allow capture of console
+    output from within bochs to file and for debugging a kernel running
+    under bochs with gdb. Contact me (welch@cwcom.net) if you're are 
+    interested.
+    
+    If CPU reports an exception not handled by the kernel (any page fault
+    not part of virtual memory support or any other exception) the kernel 
+    will display output like this and halt
+    
+            General Protection Fault Exception: 13(0)
+           CS:EIP  xxxxxxxx:xxxxxxx
+           DS xxxx ES xxxx FS xxxx GS xxxxx
+           EAX: xxxx EBX: xxxx
+           ....
+           EDI: xxxx EFLAGS: xxxx ESP: xxxx
+           cr2: xxxx
+           Stack: xxxx xxxx xxxx ...
+                  ....
+           Frames: xxxx xxxx xxxx ...
+                  ....
+                  
+    The fault type will usually be either 'General Protection' or
+    'Page Fault', see your Intel manual for the more exotic types. The
+    'EIP' number is the address of the faulting instruction. If the 'CS'
+    number is 0x20 then the exception occured in kernel mode, if it is 0x11
+    then the exception occurred in user mode. 'cr2' is the address that the
+    faulting instruction was trying to access, if the exception was a page 
+    fault. The number printed after 'Frames' are any addresses on the stack
+    that look like function addresses. 
+    
+    
+    If the kernel detects a serious problem that it will bug check, displaying
+    output like this
+    
+           Bug detected (code x, param x x x x)
+          Frames: xxx xxxx xxxx
+                  ....
+                  
+    Again the numbers printed after 'Frames' are any addresses on the stack
+    that look like function addresss. Usually the kernel will also print a
+    message describing the problem in more detail, the bug check code isn't
+    very useful at the moment. 
+    
+* Contacts
+
+    There is a mailing list for kernel development,
+    
+            ros-kernel@sid-dis.com
+           
+    The main developers use a cvs account to coordinate changes, ask 
+    rex (rex@lvcablemodem.com) for an account if you are going to be adding
+    a lot of code. Smaller patches can go to the mailing list or to the
+    relevant developer (usually the comment at the top of a module will have
+    an email address). Regular snapshots are made available for download,
+    see the mailing list for announcements.
+    
+* Legal stuff
+
+    The ReactOS project is GPL'ed, please make sure any code submitted is
+    compatible with this. 
+    
+    The NT4 ddk license agreement allows its usage for developing nt drivers
+    only. Legally therefore it can not be used to develop ReactOS, neither the
+    documentation or the sample code. I'm not a lawyer, but I doubt the
+    effiacy of 'shrinkwrap licenses' particularly on freely downloadable 
+    software. The only precendent I know of, in a Scottish court, didn't
+    upload this type of license.
+    
+    Also the 'fair use' section of copyright law allows the 'quoting' of small
+    sections from copyrighted documents, e.g. Windows API or DDK documentation
diff --git a/reactos/doc/INDEX b/reactos/doc/INDEX
new file mode 100644 (file)
index 0000000..2ec8549
--- /dev/null
@@ -0,0 +1,6 @@
+HACKING:   Some notes for adding code to ReactOS
+DIRS:      Explanation of directory layout
+INTERNALS: Some notes on kernel internals
+TODO:      Bugs and omissions, big and little things that need to be done
+NOTES:     Unsorted material, some of it is redundant
+BUGLIST:   Known bugs, please update when you find one
diff --git a/reactos/doc/INTERNALS b/reactos/doc/INTERNALS
new file mode 100644 (file)
index 0000000..e294785
--- /dev/null
@@ -0,0 +1,43 @@
+A collection of articles on kernel internals, please add to this
+
+------------------------------------------------------------------------------
+IRQ level
+------------------------------------------------------------------------------
+
+IRQ level (IRQL) is a per-processor state in ReactOS used to coordinate
+execution between ISRs and between threads. There are several levels
+
+       PASSIVE_LEVEL, APC_LEVEL: The normal level for user mode and most
+       kernel mode code. At the moment APC_LEVEL is unused.
+       
+       DISPATCH_LEVEL: At this level all irqs are still allowed but thread
+       rescheduling on the current processor is disabled. This is used by
+       the spinlock synchronization primitive to implement its uniprocessor
+       semantics (multiprocessor is more complex). It is also used for some
+       other forms of synchronization, DPCs for example. Many APIs are
+       unavailable at this IRQL, usually those that might have to wait. It
+       is recommended that you don't spend too much time at this IRQL 
+       otherwise system responsiveness will be reduced.
+       
+       > DISPATCH_LEVEL: Each irq is assigned a priority (which will be 
+       greater than DISPATCH_LEVEL). At an irq's priority level that irq,
+       lower priority irqs and thread rescheduling are disabled. Higher
+       priority irqs can still run. Very few APIs are available at IRQLs
+       greater than DISPATCH_LEVEL.
+       
+       HIGH_LEVEL: All irqs are disabled.
+
+-------------------------------------------------------------------------------
+DPCs
+-------------------------------------------------------------------------------
+
+It is a design goal not to spend too much time in ISRs, for this reason
+ISRs should postpone most processing till it can run at a lower IRQL. The
+mechanism for this is a Delayed Procedure Call (DPC). When a DPC object is
+created, it is associated with a function. The DPC object can then be inserted
+in the DPC queue from an ISR. If the IRQL on return from the ISR is less than
+DISPATCH_LEVEL the DPC queue will be drained, otherwise this will happen when
+the IRQL level drops below DISPATCH_LEVEL or the processor becomes idle. When
+the DPC queue is drained each DPC object is removed and the associated
+function is called at DISPATCH_LEVEL. A DPC object can only be inserted once,
+further insertions before it is removed will have no effect. 
diff --git a/reactos/doc/notes b/reactos/doc/notes
new file mode 100644 (file)
index 0000000..25900e9
--- /dev/null
@@ -0,0 +1,687 @@
+*** This file contains messages I've culled off the net as well
+as previous discussions all of which have useful info on fixes
+that need to be added to ReactOS. messages are between five
+dashes on a line by themselves.  If you implement the fix
+reffered to in a message, feel free to delete it from the file.
+Rex ***
+-----
+Yes with DPCs, KeDrainDpcQueue should go to HIGH_LEVEL because 
+it needs to synchronize with KeInsertDpcQueue. Also the idle thread 
+should run at DISPATCH_LEVEL and regularly drain the dpc queue, that 
+way if an irq happens and the dpc can't be executed immediately it 
+will be executed as soon as the processor is idle rather than 
+waiting for the next timer tick
+-----
+About the console driver, I think it might be quite useful to have a simple 
+way for apps to print to the screen for debugging. But when the kernel is more 
+stable, console handling should be moved to user level because console printing 
+needs to know about windows and so on which can only be done at user level.
+-----
+Subject: Re: IMSAMP-how to avoid rebooting?
+Date: 9 Nov 1998 00:40:32 -0000
+From: Charles Bryant <n51190709.ch@chch.demon.co.uk>
+Newsgroups: comp.os.ms-windows.programmer.nt.kernel-mode
+References: 1, 2 , 3 , 4
+
+In article <un264wzle.fsf@xxx.yyy.zzz>, David C. <qqqq@xxx.yyy.zzz> wrote:
+>The reason it won't unload when something is bound to it is the same
+>reason you can't unload any other driver that has an open client.  If
+>you install any driver, and have a user program (or another driver) open
+>a handle to it, and then give the "net stop" command to unload it,
+>you'll find that the unload will be delayed until the user program
+>closes its handle.
+
+When developing a driver I found this to be a considerable nuisance.
+Frequently a bug would leave an IRP stuck in the driver and I
+couldn't unload and reload a fixed version. While reading NTDDK.H I
+found a suspicious constant and discovered that the Flags field in
+the device (the one which you OR in DO_BUFFERED_IO or DO_DIRECT_IO)
+has a bit called DO_UNLOAD_PENDING. By experiment I confirmed that
+this bit is set when you do 'net stop', so a driver can check it
+periodically (e.g. from a timer DPC every ten seconds) and cancel all
+queued IRPs if it is found to be set.
+
+Since this is not documented anywhere that I can find, it might be
+unwise to rely on it for production code, but it is very useful for
+debugging. Maybe someone with internals knowledge can comment on the
+reliability of it.
+-----
+Subject: Re: Kernel bugs
+Date: Fri, 23 Oct 1998 12:08:36 -0700
+From: rex <rex@lvcablemodem.com>
+To: Jason Filby <jasonfilby@yahoo.com>
+References: 1
+
+Jason Filby wrote:
+
+> Hi,
+>
+> Ok -- here's most of what I get when I press a key:
+>
+> Page fault detected at address 1fd4 with eip c042f794
+> Recursive page fault detected
+> Exception 14(2)
+> CS:EIP 20:c042f794
+>
+> Rex -- do you know of anyway to find out which function in what file
+> is causing the exception? I know that for problems in the kernel, you
+> just look in the ntoskrnl\kernel.sym file and find the EIP value which
+> matches the one given in the exception debug text. But what about
+> modules? How can we track exceptions that occur in functions in modules?
+>
+
+I know this is a little belated, but I thought I'd take astab at answering
+this anyway.  add an option to the
+makefile for the module to generate a listing file with
+symbol information.  Then, on a boot test, note the
+address that the module is loaded at, and subtract
+this from the EIP value.  add any offset used in the
+module link specification (I dont think there currently
+is one), and look for the last symbol with a lower
+address offset.
+
+Brian, I have an idea on how to make this exception
+dump information a little more useful.  We should
+have the load information for the load modules
+in memory somewhere.  Perhaps the exception
+dump could check offending addresses to see if
+they lie in the kernel or in a module, and if they
+lie in a module the proper offset could be subtracted
+and this number could be displayed seperately.  If
+I get a chance today, I'll make this change and send
+it to ya.
+
+Rex.
+-----
+Subject: [ros-kernel] Pet peeve of the week
+Resent-Date: Sun, 25 Oct 1998 11:57:40 -0600
+Resent-From: ros-kernel@sid-dis.com
+Date: Sun, 25 Oct 1998 09:53:48 -0800
+From: rex <rex@lvcablemodem.com>
+Reply-To: <ros-kernel@sid-dis.com>
+To: ReactOS Kernel Forum <ros-kernel@sid-dis.com>
+
+Hi all,
+
+I guess it's about time to start another mailstorm
+on the list. :)
+
+I have a suggestion for a change to the kernel.
+It not a very big change, and I hope everyone
+will agree that it makes sense.
+
+There is a structure used in many places in the
+kernel called LARGE_INTEGER.  the is also
+a version called ULARGE_INTEGER, but it
+is not used at all as far as I can tell.  this structure
+is equivalent to a long long int.  You can literally
+cast a pointer to a LARGE_INTEGER to a
+long long int and all manipulation will work
+seemlessly. My suggestion is that we replace the
+use of this structure with long long ints.  Even
+microsoft, in their infinite wisdom, has made this
+suggestion in the DDK documentation.  If you're
+wondering where, look at the RTL functions
+that manipulate LARGE_INTEGER structs.
+
+Replacing LI's with long long ints will work
+because they are binary compatable.  All software
+compiled to use LI's will manipulate long long ints
+correctly and vice versa. There is one problem
+with this suggestion: the LARGE_INTEGER type
+is a structure containing 2 members.  Any code
+that accesses the structure by members will break.
+I think the kernel side impact is minimal, and is
+worth the change.  However, the structure is used
+in several of the Win32 API functions, and needs
+to remain there.  I think we build a conditionally
+compiled version of the LARGE_INTEGER type.
+In kernel mode code (the kernel proper and drivers)
+the LARGE INTEGER will be the following:
+
+typedef long long int LARGE_INTEGER,
+    *PLARGE_INTEGER;
+typedef unsigned long long int ULARGE_INTEGER,
+    *PULARGE_INTEGER;
+
+and in user mode code it will expand out to the
+current definition (which by the way, is not
+strictly correct, but can't be because it uses a
+MS compiler extension).
+
+Brian, I would be willing to make the conversion
+to those kernel modules that needed it, and of
+course to the IDE driver if we want to go forward
+with the change.
+
+Lastly, I'll mention what made me consider this.
+I was fixing the timer routines, and two of the
+three problems turned out to be related to LI
+conversion problems.
+
+Rex.
+-----
+Subject:  Re: [ros-kernel] Pet peeve of the week
+Date: Thu, 29 Oct 1998 19:10:37 +0100
+From: Boudewijn <ariadne@xs4all.nl>
+To: rex@lvcablemodem.com
+References: 1
+
+Hai Rex
+
+    I think it is a good idea to wrap a makro around the member access
+to large integers.
+I haven't tested this, but do you think this is a good sugestion ?
+
+#ifdef COMPILER_LARGE_INTEGERS
+#define GET_LARGE_INTEGER_HIGH_PART(LargeInteger) ( ( LargeInteger >>
+32) )
+#define GET_LARGE_INTEGER_LOW_PART(LargeInteger) ( (LargeInteger &
+0xFFFFFFFF) )
+#define SET_LARGE_INTEGER_HIGH_PART(LargeInteger,Signed_Long) (
+LargeInteger |= ( ((LARGE_INTEGER)Signed_Long) << 32 ) )
+#define SET_LARGE_INTEGER_LOW_PART(LargeInteger,Unsigned_Long) (
+LargeInteger |= Unsigned_Long  )
+#else
+#define GET_LARGE_INTEGER_HIGH_PART(LargeInteger) (  (
+LargeInteger.HighPart) )
+#define GET_LARGE_INTEGER_LOW_PART(LargeInteger) (
+(LargeInteger.LowPart) )
+#define SET_LARGE_INTEGER_HIGH_PART(LargeInteger,Signed_Long) (
+LargeInteger.HighPart=  Signed_Long  )
+#define SET_LARGE_INTEGER_LOW_PART(LargeInteger,Unsigned_Long) (
+LargeInteger.LowPart = Unsigned_Long  )
+#endif
+
+Boudewijn
+-----
+Subject: Re: Question on "Sending buffers on the stack to asynchronous DeviceIoControl with buffered I/O"
+Date: Mon, 16 Nov 1998 11:24:57 -0800
+From: "-Paul" <paulsan@microsoftSPAM.com>
+Organization: Microsoft Corp.
+Newsgroups: microsoft.public.win32.programmer.kernel, comp.os.ms-windows.programmer.nt.kernel-mode
+References: 1
+
+Radu, I post the following information occassionally for questions such as
+yours.  I hope it helps.
+
+-Paul
+
+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.
+
+
+
+Radu Woinaroski wrote in message <364F8F6E.2434B010@scitec.com.au>...
+>Hello,
+>
+>I have a kernel-mode device driver that accepts a number of IoControl
+>commands that use buffered data transfer (METHOD_BUFFERED).
+>
+>A user mode API provides a higher level access then the DeviceIoControl
+>function.
+>
+>The function is implemented like that
+>
+>BOOL
+Something( 
+> HANDLE hDevice , 
+> int param1, 
+> int param2, 
+> DWORD * pReturn, 
+> LPOVERLAPPED pOverlapped)
+>{
+> // here a data buffer on the stack sent to asynchronous DeviceIoControl
+>call
+> int aDataIn[2];
+> aDataIn[0] = param1;
+> aDataIn[1] = param2;
+>
+> return DeviceIoControl( 
+> hDevice,
+> DO_SOMETHING_IO, 
+> aDataIn,
+> sizeof(int)*2,
+> pReturn,
+> sizeof(DWORD),
+> pOverlapped);
+>}
+>
+>The aDataIn buffer will not exist after DeviceIoControl returns (and
+>when the I/O operation terminates). I know that for buffered IO the
+>input data buffer is copyed by de IOManager to a nonpaged-pool area
+>before passing the request to driver dispatch routine (DeviceControl).
+>At the point of calling the dispatch routine (DeviceControl) the driver
+>runs in the context of the calling thread so DeviceIoControl hasn't
+>returned yet (?? or so I think) so aDataI
+n will still be valid at the
+>time IOManager copyes it to its buffer. So, this apears to work ok (at
+>least in my opinion).
+>
+>Does I/O Manager use the Input buffer from the call to the Win32
+>DeviceIoControl any where else after the first copy ?
+>
+>Is there any reason why this approach (passing a buffer on the stack to
+>a asynchronous DeviceIoControl that uses buffered I/O) wouldn't work ?
+>
+>Allocating buffers from heap and deleting them on IO completion while
+>managing asynchronous IO seems too much work ;-) .
+>
+>Thanks in advance for your opinions
+>Radu W.
+>
+>--
+>Radu Woinaroski
+>Scitec
+>Sydney, Australia
+>Radu.Woinaroski@scitec.com.au
+-----
+Subject: Re: PCI ISR problem
+Date: Fri, 20 Nov 1998 18:04:48 GMT
+From: jeh@cmkrnl.com (Jamie Hanrahan)
+Organization: Kernel Mode Systems, San Diego, CA
+Newsgroups: comp.os.ms-windows.programmer.nt.kernel-mode
+References: 1
+
+On Thu, 19 Nov 1998 15:46:13 -0600, Eric Gardiner
+<eric.gardiner@natinst.com> wrote:
+
+>I'm having problems with NT4 not hooking the interrupt line indicated by
+>a PCI device.  Here's what I'm doing:
+>
+>1)  Enumerating the PCI buses on the system (using HalGetBusData) until
+>I find my device.
+>2)  Once my device is found, I read the "Interrupt Line Register" in the
+>device's PCI config space to determine what interrupt level to pass to
+>HalGetInterruptVector.
+
+Whups!  No.  Call HalAssignSlotResources and look at the returned
+CM_RESOURCE_LIST to find the vector, level, port addresses, etc., for
+your device.  (Then pass the returned CM_RESOURCE_LIST to ExFreePool.)
+
+
+See Knowledge Base article Q152044. 
+
+        --- Jamie Hanrahan, Kernel Mode Systems, San Diego CA (jeh@cmkrnl.com)
+Drivers, internals, networks, applications, and training for VMS and Windows NT
+NT kernel driver FAQ, links, and other information:  http://www.cmkrnl.com/
+
+Please post replies, followups, questions, etc., in news, not via e-mail. 
+-----
+Subject: Re: IRP canceling
+Date: Mon, 23 Nov 1998 09:05:47 -0500
+From: Walter Oney <waltoney@oneysoft.com>
+Organization: Walter Oney Software
+Newsgroups: comp.os.ms-windows.programmer.nt.kernel-mode
+References: 1
+
+Seol,Keun Seok wrote:
+> But, if the IRP was the CurrentIrp of the Device Object,
+> the Driver's Start I/O routine will try to process the IRP.
+> In the DDK help, the Start I/O routine MUST check the current IRP's
+> Cancel bit.
+> If set, Start I/O routine must just return.
+> 
+> But I think that the IRP already completed should not be accessed. 
+
+You're absolutely right. I recommend the following code in a standard
+StartIo routine to avoid the problem you point out:
+
+VOID StartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+  {
+  KIRQL oldirql;
+  IoAcquireCancelSpinLock(&oldirql);
+  if (Irp != DeviceObject->CurrentIrp || Irp->Cancel)
+    {
+    IoReleaseCancelSpinLock(oldirql);
+    return;
+    }
+  else
+    {
+    IoSetCancelRoutine(Irp, NULL);
+    IoReleaseCancelSpinLock(oldirql);
+    }
+  . . .
+  }
+
+This dovetails with a standard cancel routine:
+
+VOID CancelRoutine(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+  {
+  if (DeviceObject->CurrentIrp == Irp)
+    {
+    IoReleaseCancelSpinLock(Irp->CancelIrql);
+    IoStartNextPacket(DeviceObject, TRUE);
+    }
+  else
+    {
+    KeRemoveEntryDeviceQueue(&DeviceObject->DeviceQueue,
+      &Irp->Tail.Overlay.DeviceQueueEntry);
+    IoReleaseCancelSpinLock(Irp->CancelIrql);
+    }
+  Irp->IoStatus.Status = STATUS_CANCELLED;
+  Irp->IoStatus.Information = 0;
+  IoCompleteRequest(Irp, IO_NO_INCREMENT);
+  }
+
+You need to remember that the C language specification requires that
+evaluation of boolean operators short circuit when the result is known.
+So, if StartIo discovers that the Irp it got as an argument is not the
+same as CurrentIrp, it will not attempt to evaulate Irp->Cancel.
+
+Now, as to why this works: StartIo gets called either by IoStartPacket
+or IoStartNextPacket. Each of them will grab the cancel spin lock and
+set CurrentIrp, then release the spin lock and call StartIo. If someone
+should sneak in on another CPU and cancel this very same IRP, your
+cancel routine will immediately release the spin lock and call
+IoStartNextPacket. One of two things will then happen. IoStartNextPacket
+may succeed in getting the cancel spin lock, whereupon it will nullify
+the CurrentIrp pointer. If another IRP is on the queue, it will remove
+it from the queue, set CurrentIrp to point to this *new* IRP, release
+the spin lock, and call StartIo. [You now have two instances of StartIo
+running on two different CPUs for two different IRPs, but it's not a
+problem because they won't be able to interfere with each other.]
+Meanwhile, your original instance of StartIo gets the cancel spin lock
+and sees that CurrentIrp is not equal to the IRP pointer it got as an
+argument, so it gives up.
+
+The second way this could play out is that StartIo gets the cancel lock
+before IoStartNextPacket does. In this case, CurrentIrp is still
+pointing to the IRP that's in the process of being cancelled and that
+StartIo got as an argument. But this IRP hasn't been completed yet (the
+CPU that's running your cancel routine is spinning inside
+IoStartNextPacket and therefore hasn't gotten to calling
+IoCompleteRequest yet), so no-one will have been able to call IoFreeIrp
+to make your pointer invalid.
+
+People may tell you that you should be using your own queues for IRPs so
+you can avoid bottlenecking the system on the global cancel spin lock.
+That's true enough, but doing it correctly with Plug and Play and Power
+management things in the way is gigantically complicated. There's a
+sample in the NT 5 beta-2 DDK called CANCEL that shows how to manage
+your own queue if you don't worry about PNP and POWER. I hear tell of an
+upcoming MSJ article by a Microsoft developer that may solve the
+complete problem.
+-----
+Subject: ANNOUNCE: ALINK v1.5
+Date: 16 Nov 1998 16:36:05 GMT
+From: anthony_w@my-dejanews.com
+Organization: Deja News - The Leader in Internet Discussion
+Newsgroups: comp.os.ms-windows.programmer.win32, comp.lang.asm.x86, comp.os.msdos.programmer
+
+ALINK is a freeware linker, creating MSDOS COM and EXE files and Win32 PE EXE
+and DLL files from OMF format OBJ and LIB files, win32-COFF format OBJ files,
+and win32 RES files.
+
+NEW for version 1.5:
+
+Win32 COFF object file support.
+
+Download it now from my home page.
+
+Anthony
+--
+anthony_w@geocities.com
+http://www.geocities.com/SiliconValley/Network/4311/index.html
+
+-----------== Posted via Deja News, The Discussion Network ==----------
+http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own    
+-----
+