1*** This file contains messages I've culled off the net as well 2as previous discussions all of which have useful info on fixes 3that need to be added to ReactOS. messages are between five 4dashes on a line by themselves. If you implement the fix 5reffered to in a message, feel free to delete it from the file. 6Rex *** 7----- 8Subject: [ros-kernel] Inside the Boot Process 9Date: Mon, 22 Mar 1999 22:05:47 +0100 10From: Emanuele Aliberti <ea@iol.it> 11 12For those working on the boot loader: in WinNt Magazine november 1998 13issue (http://www.winntmag.com/) there is a detailed description, by 14Mark Russinovich, of the r�le the MBR, NTLDR, boot.ini, ntdetect.com... 15play in the boot process ("Inside the Boot Process, Part 1"). 16----- 17Yes with DPCs, KeDrainDpcQueue should go to HIGH_LEVEL because 18it needs to synchronize with KeInsertDpcQueue. Also the idle thread 19should run at DISPATCH_LEVEL and regularly drain the dpc queue, that 20way if an irq happens and the dpc can't be executed immediately it 21will be executed as soon as the processor is idle rather than 22waiting for the next timer tick 23----- 24About the console driver, I think it might be quite useful to have a simple 25way for apps to print to the screen for debugging. But when the kernel is more 26stable, console handling should be moved to user level because console printing 27needs to know about windows and so on which can only be done at user level. 28----- 29Subject: Re: IMSAMP-how to avoid rebooting? 30Date: 9 Nov 1998 00:40:32 -0000 31From: Charles Bryant <n51190709.ch@chch.demon.co.uk> 32Newsgroups: comp.os.ms-windows.programmer.nt.kernel-mode 33References: 1, 2 , 3 , 4 34 35In article <un264wzle.fsf@xxx.yyy.zzz>, David C. <qqqq@xxx.yyy.zzz> wrote: 36>The reason it won't unload when something is bound to it is the same 37>reason you can't unload any other driver that has an open client. If 38>you install any driver, and have a user program (or another driver) open 39>a handle to it, and then give the "net stop" command to unload it, 40>you'll find that the unload will be delayed until the user program 41>closes its handle. 42 43When developing a driver I found this to be a considerable nuisance. 44Frequently a bug would leave an IRP stuck in the driver and I 45couldn't unload and reload a fixed version. While reading NTDDK.H I 46found a suspicious constant and discovered that the Flags field in 47the device (the one which you OR in DO_BUFFERED_IO or DO_DIRECT_IO) 48has a bit called DO_UNLOAD_PENDING. By experiment I confirmed that 49this bit is set when you do 'net stop', so a driver can check it 50periodically (e.g. from a timer DPC every ten seconds) and cancel all 51queued IRPs if it is found to be set. 52 53Since this is not documented anywhere that I can find, it might be 54unwise to rely on it for production code, but it is very useful for 55debugging. Maybe someone with internals knowledge can comment on the 56reliability of it. 57----- 58Subject: Re: Kernel bugs 59Date: Fri, 23 Oct 1998 12:08:36 -0700 60From: rex <rex@lvcablemodem.com> 61To: Jason Filby <jasonfilby@yahoo.com> 62References: 1 63 64Jason Filby wrote: 65 66> Hi, 67> 68> Ok -- here's most of what I get when I press a key: 69> 70> Page fault detected at address 1fd4 with eip c042f794 71> Recursive page fault detected 72> Exception 14(2) 73> CS:EIP 20:c042f794 74> 75> Rex -- do you know of anyway to find out which function in what file 76> is causing the exception? I know that for problems in the kernel, you 77> just look in the ntoskrnl\kernel.sym file and find the EIP value which 78> matches the one given in the exception debug text. But what about 79> modules? How can we track exceptions that occur in functions in modules? 80> 81 82I know this is a little belated, but I thought I'd take astab at answering 83this anyway. add an option to the 84makefile for the module to generate a listing file with 85symbol information. Then, on a boot test, note the 86address that the module is loaded at, and subtract 87this from the EIP value. add any offset used in the 88module link specification (I dont think there currently 89is one), and look for the last symbol with a lower 90address offset. 91 92Brian, I have an idea on how to make this exception 93dump information a little more useful. We should 94have the load information for the load modules 95in memory somewhere. Perhaps the exception 96dump could check offending addresses to see if 97they lie in the kernel or in a module, and if they 98lie in a module the proper offset could be subtracted 99and this number could be displayed seperately. If 100I get a chance today, I'll make this change and send 101it to ya. 102 103Rex. 104----- 105Subject: Re: Question on "Sending buffers on the stack to asynchronous DeviceIoControl with buffered I/O" 106Date: Mon, 16 Nov 1998 11:24:57 -0800 107From: "-Paul" <paulsan@microsoftSPAM.com> 108Organization: Microsoft Corp. 109Newsgroups: microsoft.public.win32.programmer.kernel, comp.os.ms-windows.programmer.nt.kernel-mode 110References: 1 111 112Radu, I post the following information occassionally for questions such as 113yours. I hope it helps. 114 115-Paul 116 117Here is an explanation of buffers and DeviceIoControl. 118 119First, here are the parameters, 120 121BOOL DeviceIoControl( 122 HANDLE hDevice, // handle to device of interest 123 DWORD dwIoControlCode, // control code of operation to perform 124 LPVOID lpInBuffer, // pointer to buffer to supply input data 125 DWORD nInBufferSize, // size of input buffer 126 LPVOID lpOutBuffer, // pointer to buffer to receive output data 127 DWORD nOutBufferSize, // size of output buffer 128 LPDWORD lpBytesReturned, // pointer to variable to receive output byte 129count 130 LPOVERLAPPED lpOverlapped // pointer to overlapped structure for 131asynchronous operation 132 ); 133 134METHOD_BUFFERED 135 136user-mode perspective 137 138lpInBuffer - optional, contains data that is written to the driver 139lpOutBuffer - optional, contains data that is read from the driver after 140the call has completed 141 142lpInBuffer and lpOutBuffer can be two buffers or a single shared buffer. 143If a shared buffer, lpInBuffer is overwritten by lpOutBuffer. 144 145 146I/O Manager perspective 147 148examines nInBufferSize and nOutBufferSize. Allocates memory from non-paged 149pool and puts the address of this pool in Irp->AssociatedIrp.SystemBuffer. 150The size of this buffer is equal to the size of the larger of the two 151bufferes. This buffer is accessible at any IRQL. 152 153copies nInBufferSize to irpSp->Parameters.DeviceIoControl.InputBufferLength 154copies nOutBufferSize to 155irpSp->Parameters.DeviceIoControl.OutputBufferLength 156copies contents of lpInBuffer to SystemBuffer allocated above 157calls your driver 158 159 160 161Device Driver perspective 162 163you have one buffer, Irp->AssociatedIrp.SystemBuffer. You read input data 164from this buffer and you write output data to the same buffer, overwriting 165the input data. 166 167Before calling IoCompleteRequest, you must 168- set IoStatus.Status to an approriate NtStatus 169- if IoStatus.Status == STATUS_SUCCESS 170 set IoStatus.Information to the 171 number of bytes you want copied 172 from the SystemBuffer back into 173 lpOutBuffer. 174 175 176I/O Manager Completion Routine perspective 177 178looks at IoStatus block, if IoStatus.Status = STATUS_SUCCESS, copies the 179number of bytes specified by IoStatus.Information from 180Irp->AssociatedIrp.SystemBuffer into lpOutBuffer 181completes the request 182 183 184 185 186 187 188METHOD_IN_DIRECT 189 190user-mode perspective 191 192lpInBuffer - optional, contains data that is written to the driver. This 193buffer is used in the exact same fashion as METHOD_BUFFERED. To avoid 194confusion, mentally rename this buffer to lpControlBuffer. This is 195typically a small, optional buffer that might contain a control structure 196with useful information for the device driver. This buffer is smal and is 197double buffered. 198 199lpOutBuffer - NOT OPTIONAL, This LARGE buffer contains data that is read by 200the driver. To avoid confusion, mentally rename this buffer to 201lpDataTransferBuffer. This is physically the same buffer that the device 202driver will read from. There is no double buffering. Technically, this 203buffer is still optional, but since you are using this buffering method, 204what would be the point??? 205 206I/O Manager perspective 207 208If lpInBuffer exists, allocates memory from non-paged pool and puts the 209address of this pool in Irp->AssociatedIrp.SystemBuffer. This buffer is 210accessible at any IRQL. 211 212copies nInBufferSize to irpSp->Parameters.DeviceIoControl.InputBufferLength 213copies nOutBufferSize to 214irpSp->Parameters.DeviceIoControl.OutputBufferLength 215copies contents of lpInBuffer to SystemBuffer allocated above 216So far this is completely identical to METHOD_BUFFERED. Most likely 217lpInBuffer (mentally renamed to lpControlBuffer) is very small in size. 218 219For lpOutBuffer (mentally renamed to lpDataTransferBuffer), an MDL is 220allocated. lpOutBuffer is probed and locked into memory. Then, the user 221buffer virtual addresses are checked to be sure they are readable in the 222caller's access mode. 223 224The MDL is address is stored in Irp->MdlAddress. 225Your driver is called. 226 227 228Device Driver perspective 229 230The device driver can read the copy of lpOutBuffer via 231Irp->AssociatedIrp.SystemBuffer. Anything written by the device driver to 232this buffer is lost. The I/O Manager does not copy any data back to the 233user-mode buffers as it did in the completion routine for METHOD_BUFFERED. 234Art Baker's book is wrong in this respect (page 168, "data going from the 235driver back to the caller is passed through an intermediate system-space 236buffer" and page 177, "When the IOCTL IRP is completed, the contents of the 237system buffer will be copied back into the callers original output buffer". 238 239The device driver accesses the Win32 buffer directly via Irp->MdlAddress. 240The driver uses whatever Mdl API's to read the buffer. Usually, this 241buffer is to be written to some mass storage media or some similar 242operation. Since this is a large data transfer, assume a completion 243routine is required. 244 245mark the Irp pending 246queue it 247return status pending 248 249 250 251 252Device Driver Completion Routine perspective 253 254standard completion routine operations 255set IoStatus.Status to an approriate NtStatus 256IoStatus.Information is not needed 257completete the request 258 259 260 261 262I/O Manager Completion Routine perspective 263 264standard I/O Manager completion routine operations 265unmap the pages 266deallocate the Mdl 267complete the request 268 269 270 271 272 273METHOD_OUT_DIRECT 274 275user-mode perspective 276 277lpInBuffer - optional, contains data that is written to the driver. This 278buffer is used in the exact same fashion as METHOD_BUFFERED. To avoid 279confusion, mentally rename this buffer to lpControlBuffer. This is 280typically a small, optional buffer that might contain a control structure 281with useful information for the device driver. This buffer is smal and is 282double buffered. 283 284lpOutBuffer - NOT OPTIONAL, This LARGE buffer contains data that is written 285by the driver and read by the wer-mode application when the request is 286completed. To avoid confusion, mentally rename this buffer to 287lpDataTransferBuffer. This is physically the same buffer that the device 288driver will write to. There is no double buffering. Technically, this 289buffer is still optional, but since you are using this buffering method, 290what would be the point??? 291 292I/O Manager perspective 293 294If lpInBuffer exists, allocates memory from non-paged pool and puts the 295address of this pool in Irp->AssociatedIrp.SystemBuffer. This buffer is 296accessible at any IRQL. 297 298copies nInBufferSize to irpSp->Parameters.DeviceIoControl.InputBufferLength 299copies nOutBufferSize to 300irpSp->Parameters.DeviceIoControl.OutputBufferLength 301copies contents of lpInBuffer to SystemBuffer allocated above 302So far this is completely identical to METHOD_BUFFERED. Most likely 303lpInBuffer (mentally renamed to lpControlBuffer) is very small in size. 304 305For lpOutBuffer (mentally renamed to lpDataTransferBuffer), an MDL is 306allocated. lpOutBuffer is probed and locked into memory. Then the user 307buffer's addresses are checked to make sure the caller could write to them 308in the caller's access mode. 309 310The MDL is address is stored in Irp->MdlAddress. 311Your driver is called. 312 313 314Device Driver perspective 315 316The device driver can read the copy of lpOutBuffer via 317Irp->AssociatedIrp.SystemBuffer. Anything written by the device driver to 318this buffer is lost. 319 320The device driver accesses the Win32 buffer directly via Irp->MdlAddress. 321The driver uses whatever Mdl API's to write data to the buffer. Usually, 322this buffer is to be read from some mass storage media or some similar 323operation. Since this is a large data transfer, assume a completion 324routine is required. 325 326mark the Irp pending 327queue it 328return status pending 329 330 331 332 333Device Driver Completion Routine perspective 334 335standard completion routine operations 336set IoStatus.Status to an approriate NtStatus 337IoStatus.Information is not needed 338completete the request 339 340 341 342 343I/O Manager Completion Routine perspective 344 345standard I/O Manager completion routine operations 346unmap the pages 347deallocate the Mdl 348complete the request 349 350 351 352 353METHOD_NEITHER 354 355I/O Manager perspective 356 357Irp->UserBuffer = lpOutputBuffer; 358IrpSp->Parameters.DeviceIoControl.Type3InputBuffer = lpInputBuffer; 359 360No comments here. Don't use METHOD_DIRECT unless you know what you are 361doing. Simple rule. 362 363If your IOCtl involves no data transfer buffers, then METHOD_NEITHER is the 364fastest path through the I/O Manager that involves an Irp. 365 366 367 368 369Final Comment 370 371Don't touch Irp->UserBuffer. This is a bookmark for the I/O Manager. Two 372major problems can occur. 1 - page fault at high IRQL, or 2 - you write 373something to Irp->UserBuffer and the I/O Manager overwrites you in its 374completion routine. File systems access Irp->UserBuffer, but FSD writers 375know all of the above and know when it is safe to touch Irp->UserBuffer. 376 377 378 379Radu Woinaroski wrote in message <364F8F6E.2434B010@scitec.com.au>... 380>Hello, 381> 382>I have a kernel-mode device driver that accepts a number of IoControl 383>commands that use buffered data transfer (METHOD_BUFFERED). 384> 385>A user mode API provides a higher level access then the DeviceIoControl 386>function. 387> 388>The function is implemented like that 389> 390>BOOL 391Something( 392> HANDLE hDevice , 393> int param1, 394> int param2, 395> DWORD * pReturn, 396> LPOVERLAPPED pOverlapped) 397>{ 398> // here a data buffer on the stack sent to asynchronous DeviceIoControl 399>call 400> int aDataIn[2]; 401> aDataIn[0] = param1; 402> aDataIn[1] = param2; 403> 404> return DeviceIoControl( 405> hDevice, 406> DO_SOMETHING_IO, 407> aDataIn, 408> sizeof(int)*2, 409> pReturn, 410> sizeof(DWORD), 411> pOverlapped); 412>} 413> 414>The aDataIn buffer will not exist after DeviceIoControl returns (and 415>when the I/O operation terminates). I know that for buffered IO the 416>input data buffer is copyed by de IOManager to a nonpaged-pool area 417>before passing the request to driver dispatch routine (DeviceControl). 418>At the point of calling the dispatch routine (DeviceControl) the driver 419>runs in the context of the calling thread so DeviceIoControl hasn't 420>returned yet (?? or so I think) so aDataI 421n will still be valid at the 422>time IOManager copyes it to its buffer. So, this apears to work ok (at 423>least in my opinion). 424> 425>Does I/O Manager use the Input buffer from the call to the Win32 426>DeviceIoControl any where else after the first copy ? 427> 428>Is there any reason why this approach (passing a buffer on the stack to 429>a asynchronous DeviceIoControl that uses buffered I/O) wouldn't work ? 430> 431>Allocating buffers from heap and deleting them on IO completion while 432>managing asynchronous IO seems too much work ;-) . 433> 434>Thanks in advance for your opinions 435>Radu W. 436> 437>-- 438>Radu Woinaroski 439>Scitec 440>Sydney, Australia 441>Radu.Woinaroski@scitec.com.au 442----- 443Subject: Re: PCI ISR problem 444Date: Fri, 20 Nov 1998 18:04:48 GMT 445From: jeh@cmkrnl.com (Jamie Hanrahan) 446Organization: Kernel Mode Systems, San Diego, CA 447Newsgroups: comp.os.ms-windows.programmer.nt.kernel-mode 448References: 1 449 450On Thu, 19 Nov 1998 15:46:13 -0600, Eric Gardiner 451<eric.gardiner@natinst.com> wrote: 452 453>I'm having problems with NT4 not hooking the interrupt line indicated by 454>a PCI device. Here's what I'm doing: 455> 456>1) Enumerating the PCI buses on the system (using HalGetBusData) until 457>I find my device. 458>2) Once my device is found, I read the "Interrupt Line Register" in the 459>device's PCI config space to determine what interrupt level to pass to 460>HalGetInterruptVector. 461 462Whups! No. Call HalAssignSlotResources and look at the returned 463CM_RESOURCE_LIST to find the vector, level, port addresses, etc., for 464your device. (Then pass the returned CM_RESOURCE_LIST to ExFreePool.) 465 466 467See Knowledge Base article Q152044. 468 469 --- Jamie Hanrahan, Kernel Mode Systems, San Diego CA (jeh@cmkrnl.com) 470Drivers, internals, networks, applications, and training for VMS and Windows NT 471NT kernel driver FAQ, links, and other information: http://www.cmkrnl.com/ 472 473Please post replies, followups, questions, etc., in news, not via e-mail. 474----- 475Subject: Re: IRP canceling 476Date: Mon, 23 Nov 1998 09:05:47 -0500 477From: Walter Oney <waltoney@oneysoft.com> 478Organization: Walter Oney Software 479Newsgroups: comp.os.ms-windows.programmer.nt.kernel-mode 480References: 1 481 482Seol,Keun Seok wrote: 483> But, if the IRP was the CurrentIrp of the Device Object, 484> the Driver's Start I/O routine will try to process the IRP. 485> In the DDK help, the Start I/O routine MUST check the current IRP's 486> Cancel bit. 487> If set, Start I/O routine must just return. 488> 489> But I think that the IRP already completed should not be accessed. 490 491You're absolutely right. I recommend the following code in a standard 492StartIo routine to avoid the problem you point out: 493 494VOID StartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp) 495 { 496 KIRQL oldirql; 497 IoAcquireCancelSpinLock(&oldirql); 498 if (Irp != DeviceObject->CurrentIrp || Irp->Cancel) 499 { 500 IoReleaseCancelSpinLock(oldirql); 501 return; 502 } 503 else 504 { 505 IoSetCancelRoutine(Irp, NULL); 506 IoReleaseCancelSpinLock(oldirql); 507 } 508 . . . 509 } 510 511This dovetails with a standard cancel routine: 512 513VOID CancelRoutine(PDEVICE_OBJECT DeviceObject, PIRP Irp) 514 { 515 if (DeviceObject->CurrentIrp == Irp) 516 { 517 IoReleaseCancelSpinLock(Irp->CancelIrql); 518 IoStartNextPacket(DeviceObject, TRUE); 519 } 520 else 521 { 522 KeRemoveEntryDeviceQueue(&DeviceObject->DeviceQueue, 523 &Irp->Tail.Overlay.DeviceQueueEntry); 524 IoReleaseCancelSpinLock(Irp->CancelIrql); 525 } 526 Irp->IoStatus.Status = STATUS_CANCELLED; 527 Irp->IoStatus.Information = 0; 528 IoCompleteRequest(Irp, IO_NO_INCREMENT); 529 } 530 531You need to remember that the C language specification requires that 532evaluation of boolean operators short circuit when the result is known. 533So, if StartIo discovers that the Irp it got as an argument is not the 534same as CurrentIrp, it will not attempt to evaulate Irp->Cancel. 535 536Now, as to why this works: StartIo gets called either by IoStartPacket 537or IoStartNextPacket. Each of them will grab the cancel spin lock and 538set CurrentIrp, then release the spin lock and call StartIo. If someone 539should sneak in on another CPU and cancel this very same IRP, your 540cancel routine will immediately release the spin lock and call 541IoStartNextPacket. One of two things will then happen. IoStartNextPacket 542may succeed in getting the cancel spin lock, whereupon it will nullify 543the CurrentIrp pointer. If another IRP is on the queue, it will remove 544it from the queue, set CurrentIrp to point to this *new* IRP, release 545the spin lock, and call StartIo. [You now have two instances of StartIo 546running on two different CPUs for two different IRPs, but it's not a 547problem because they won't be able to interfere with each other.] 548Meanwhile, your original instance of StartIo gets the cancel spin lock 549and sees that CurrentIrp is not equal to the IRP pointer it got as an 550argument, so it gives up. 551 552The second way this could play out is that StartIo gets the cancel lock 553before IoStartNextPacket does. In this case, CurrentIrp is still 554pointing to the IRP that's in the process of being cancelled and that 555StartIo got as an argument. But this IRP hasn't been completed yet (the 556CPU that's running your cancel routine is spinning inside 557IoStartNextPacket and therefore hasn't gotten to calling 558IoCompleteRequest yet), so no-one will have been able to call IoFreeIrp 559to make your pointer invalid. 560 561People may tell you that you should be using your own queues for IRPs so 562you can avoid bottlenecking the system on the global cancel spin lock. 563That's true enough, but doing it correctly with Plug and Play and Power 564management things in the way is gigantically complicated. There's a 565sample in the NT 5 beta-2 DDK called CANCEL that shows how to manage 566your own queue if you don't worry about PNP and POWER. I hear tell of an 567upcoming MSJ article by a Microsoft developer that may solve the 568complete problem. 569----- 570The END. 571