Wednesday, December 20, 2006

DeviceMock. Concerned IRP parameters

In general, mock objects are configurable with names of methods are expected to be called by the SUT and parameter values of these methods. A call or series of calls of an expected method and list of the corresponding parameter values is called as an expectation.
In case of the driver, IRPs sent to the device are used instead of methods calls. So expectation will consist of an IRP along with their parameters that is expected to be sent to the device by the SUT.
Thus we need to discover IRP parameters used to resolve whether the considered IRP matches one of the expectations or does not.
The first and obvious candidates to these parameters are the major and minor function codes. These codes are hold by the MajorFunction and MinorFunction fields of the IO_STACK_LOCATION structure. The IO_STACK_LOCATION structure represents an IRP subrequest that contains data are specific to the device handling the IRP among other devices driver stack contains. To obtain the IO_STACK_LOCATION pointer the device invokes the IoGetCurrentIrpStackLocation function.
Besides the function codes, the IO_STACK_LOCATION contains other parameters that are specific to the major function code of the IRP. There are three major functions code whose parameter are to be considered. These are IRP_MJ_READ, IRP_MJ_WRITE and IRP_MJ_DEVICE_CONTROL functions code. An IRP with the IRP_MJ_DEVICE_CONTROL major function code has the Parameters.DeviceIoControl field of the IO_STACK_LOCATION structure. This field is an anonymous structure, which has the IoControlCode field that indicates I/O control code used to select an operation the device should perform.
Other parameters of IRPs with the mentioned functions codes depends on what of the data transfer mechanisms is used. There are three data transfer mechanisms:
  • Buffered I/O
    • For the IRP_MJ_READ and IRP_MJ_WRITE requests this mechanism is used when the Flags field of the DEVICE_OBJECT structure has the DO_BUFFERED_IO flag set. AssociatedIrp.SystemBuffer field of the IRP points to copy of the user-mode buffer. The Parameters.Read.Length and Parameters.Write.Length fields of the of the IO_STACK_LOCATION structure indicate the size in bytes of the buffer.

    • For the IRP_MJ_DEVICE_CONTROL the used mechanism is defined by the Method field of the I/O control code.

      • When this field is set to the METHOD_BUFFERED value, the AssociatedIrp.SystemBuffer field of the IRP points to copy of the user-mode buffer. The Parameters.DeviceIoControl.InputBufferLength or Parameters.DeviceIoControl.OutputBufferLength fields of the IO_STACK_LOCATION structure indicate how many bytes the device may accordingly read or write from or to the buffer depending on the request type.
      • When the Method field is set to the METHOD_OUT_DIRECT value, the AssociatedIrp.SystemBuffer field of the IRP point to copy of user-mode buffer. The Parameters.DeviceIoControl.InputBufferLength field of the IO_STACK_LOCATION structure indicates how many bytes the device may read from the buffer. Transfering data from the device to caller is performed using the Direct I/O mechanism as will be described later.
      • When the Method field is set to the METHOD_IN_DIRECT value, the AssociatedIrp.SystemBuffer field of the IRP point to copy of user-mode buffer. The Parameters.DeviceIoControl.OutputBufferLength field of the IO_STACK_LOCATION structure indicates how many bytes the device may write to the buffer. Transfering data to the device from caller is performed using the Direct I/O mechanism as will be described later.
  • Direct I/O
    • For the IRP_MJ_READ and IRP_MJ_WRITE requests this mechanism is used when the Flags field of the DEVICE_OBJECT structure has the DO_DIRECT_IO flag set. The MdlAddress field of the IRP specifies a MDL that describes memory pages of the user-mode data buffer.
    • For the IRP_MJ_DEVICE_CONTROL the used mechanism is defined by the Method field of the I/O control code.
      • When the Method field is set to the METHOD_OUT_DIRECT value, the MdlAddress field of the IRP specifies a MDL that describes memory pages of the user-mode data buffer. The IRP handler stores data transferred from the device to this buffer.
      • When the Method field is set to the METHOD_IN_DIRECT value, the MdlAddress field of the IRP specifies a MDL that describes memory pages of the user-mode data buffer. The buffer contains data to be transferred by the IRP handler to the device.
  • Neither Buffered nor Direct I/O.
    • For the IRP_MJ_READ and IRP_MJ_WRITE requests this mechanism is used when the Flags field of the DEVICE_OBJECT structure has neither the DO_DIRECT_IO or DO_BUFFERED_IO flag set. The UserBuffer field of the IRP contains address of the user-mode buffer. The Parameters.Read.Length or Parameters.Write.Length fields of the IO_STACK_LOCATION structure indicate how many bytes the device may accordingly read or write from or to the buffer depending on the request type.
    • For the IRP_MJ_DEVICE_CONTROL the used mechanism is used when the Method field of the I/O control code has the METHOD_NEITHER value. The Parameters.DeviceIoControl.Type3InputBuffer field of the IO_STACK_LOCATION structure points to the user-mode input buffer. The Parameters.DeviceIoControl.InputBufferLength field of the IO_STACK_LOCATION structure indicates how many bytes the device may read from the input buffer. The user-mode output buffer is indicated with the UserBuffer field of the IRP. The number of bytes the device may write to this buffer is specified in the Parameters.DeviceIoControl.OutputBufferLength field of the IO_STACK_LOCATION structure.
Besides the IRP parameters themselves it would be useful to add constraints for the data contained in the input buffers the IRP specifies. However, it will be a different task.

No comments: