|
本帖最后由 sunsea 于 2021-11-25 14:38 编辑
读了一下SVBus的源代码。
SVBus在这方面处理是相当直接的。
直接构造IRP下发给下层“物理”设备(类似于\\.\PhysicalDrive0这种东西),算出起始扇区和长度后直接读取,直来直去,纯粹是“应上级请求”,上层要求什么就读什么。
所以我个人认为还是刚刚启动时,SVBus作为SCSI Miniport组设备,启动相当早,没有得到Windows的高速的USB或者其他磁盘等驱动。或者Windows为了识别文件系统等可能读取很多数据。此外驱动对读写请求不是即时同步处理的,是保存到内部队列交给别的线程完成的,这也可能是一个原因:请求太碎太多。这大概算个优化问题。
以及,目前并不清楚NT以后怎么直接呼叫int13。我怀疑已经被全部破坏掉了。
贴代码:
- // zero start sector and sector count
- StartSector = 0;
- SectorCount = 0;
- // check for read / write / verify 16 command
- if(Cdb->AsByte[0] == SCSIOP_READ16 || Cdb->AsByte[0] == SCSIOP_WRITE16 || Cdb->AsByte[0] == SCSIOP_VERIFY16)
- {
- // convert start LBA and transfer length to start sector and sector count
- REVERSE_BYTES_QUAD(&StartSector,&Cdb->CDB16.LogicalBlock[0]);
- REVERSE_BYTES(&SectorCount,&Cdb->CDB16.TransferLength[0]);
- }
- // check for read / write / verify command
- else if(Cdb->AsByte[0] == SCSIOP_READ || Cdb->AsByte[0] == SCSIOP_WRITE || Cdb->AsByte[0] == SCSIOP_VERIFY)
- {
- // convert start LBA and transfer length to start sector and sector count
- StartSector = ((ULONG)Cdb->CDB10.LogicalBlockByte0 << 24) | ((ULONG)Cdb->CDB10.LogicalBlockByte1 << 16) | ((ULONG)Cdb->CDB10.LogicalBlockByte2 << 8) | Cdb->CDB10.LogicalBlockByte3;
- SectorCount = ((ULONG)Cdb->CDB10.TransferBlocksMsb << 8) | Cdb->CDB10.TransferBlocksLsb;
- }
- // check for a disk access beyond the limit of the image size
- if(StartSector + SectorCount > DeviceExtension->Disk.ImageSizeInLBAs)
- {
- // return SCSI_SENSE_ILLEGAL_REQUEST
- Srb->SenseInfoBufferLength = (UCHAR)MemCopy(Srb->SenseInfoBuffer,Srb->SenseInfoBufferLength,&DeviceExtension->Disk.SenseData,(ULONG)sizeof(SENSE_DATA));
- Srb->DataTransferLength = 0;
- Srb->SrbStatus = SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_ERROR;
- Status = STATUS_INVALID_PARAMETER;
- break;
- }
- // calculate length of transfer
- Length = SectorCount * DeviceExtension->Disk.SectorSize;
- // SRB data buffer is valid and transfer length did not match the SRB data transfer length
- if(Srb->DataBuffer != NULL && Length != Srb->DataTransferLength)
- {
- // return SCSI_SENSE_ILLEGAL_REQUEST
- Srb->SenseInfoBufferLength = (UCHAR)MemCopy(Srb->SenseInfoBuffer,Srb->SenseInfoBufferLength,&DeviceExtension->Disk.SenseData,(ULONG)sizeof(SENSE_DATA));
- Srb->DataTransferLength = 0;
- Srb->SrbStatus = SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_ERROR;
- Status = STATUS_INVALID_PARAMETER;
- break;
- }
- // transfer length is not a multiple of sector size
- if(Length % DeviceExtension->Disk.SectorSize != 0)
- {
- // return SCSI_SENSE_ILLEGAL_REQUEST
- Srb->SenseInfoBufferLength = (UCHAR)MemCopy(Srb->SenseInfoBuffer,Srb->SenseInfoBufferLength,&DeviceExtension->Disk.SenseData,(ULONG)sizeof(SENSE_DATA));
- Srb->DataTransferLength = 0;
- Srb->SrbStatus = SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_ERROR;
- Status = STATUS_INVALID_PARAMETER;
- break;
- }
- // return success on zero sectors to transfer or verify only command
- if(SectorCount == 0 || Cdb->AsByte[0] == SCSIOP_VERIFY16 || Cdb->AsByte[0] == SCSIOP_VERIFY)
- {
- Srb->DataTransferLength = 0;
- break;
- }
- // get nonpaged system space virtual address for the buffer
- sysAddr = MmGetSystemAddressForMdlSafe(Irp->MdlAddress,HighPagePriority);
- if(sysAddr == NULL)
- {
- // return SCSI_SENSE_ILLEGAL_REQUEST
- Srb->SenseInfoBufferLength = (UCHAR)MemCopy(Srb->SenseInfoBuffer,Srb->SenseInfoBufferLength,&DeviceExtension->Disk.SenseData,(ULONG)sizeof(SENSE_DATA));
- Srb->DataTransferLength = 0;
- Srb->SrbStatus = SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_ERROR;
- Status = STATUS_INSUFFICIENT_RESOURCES;
- break;
- }
- // calculate buffer address from base virtual address and nonpaged system space virtual address
- buffer = (PVOID)(((SIZE_T)Srb->DataBuffer - (SIZE_T)MmGetMdlVirtualAddress(Irp->MdlAddress)) + (SIZE_T)sysAddr);
- // calculate start offset on the physical disk
- offset.QuadPart = (LONGLONG)(DeviceExtension->Disk.ImageStartOffsetInBytes + StartSector * DeviceExtension->Disk.SectorSize);
- // check if file object is valid
- if(DeviceExtension->Disk.FileObject == NULL)
- {
- // open disk file
- Status = DiskOpenFile(StartContext);
- if(!NT_SUCCESS(Status))
- {
- Srb->DataTransferLength = 0;
- Srb->SrbStatus = SRB_STATUS_BUSY;
- Status = STATUS_DEVICE_NOT_READY;
- break;
- }
- }
- // 0x28 READ (10) or 0x88 READ (16)
- if(Cdb->AsByte[0] == SCSIOP_READ || Cdb->AsByte[0] == SCSIOP_READ16)
- {
- // allocate memory for temporary read buffer
- // We can not use the buffer address here like in the write code below. We have to
- // use double buffering, otherwise we get a MEMORY MANAGEMENT BSOD on Windows 10.
- // Reason is the MmProbeAndLockPages call in IoBuildSynchronousFsdRequest function,
- // which probes the pages for IoReadAccess.
- tmpBuffer = ExAllocatePoolWithTag(PagedPool,(SIZE_T)Length,SVBUS_POOL_TAG);
- if(tmpBuffer == NULL)
- {
- Srb->DataTransferLength = 0;
- Srb->SrbStatus = SRB_STATUS_ERROR;
- Status = STATUS_INSUFFICIENT_RESOURCES;
- break;
- }
- // read from the physical disk
- Status = ReadWritePhysicalDisk(DeviceExtension->Disk.FileDeviceObject,DeviceExtension->Disk.FileObject,IRP_MJ_READ,tmpBuffer,Length,&offset);
- if(!NT_SUCCESS(Status))
- {
- ExFreePoolWithTag(tmpBuffer,SVBUS_POOL_TAG);
- Srb->DataTransferLength = 0;
- Srb->SrbStatus = SRB_STATUS_ERROR;
- break;
- }
- // copy data from temporary buffer to buffer
- RtlCopyMemory(buffer,tmpBuffer,(SIZE_T)Length);
- // free temporary buffer memory
- ExFreePoolWithTag(tmpBuffer,SVBUS_POOL_TAG);
- // set returned read length
- Irp->IoStatus.Information = Length;
- Srb->DataTransferLength = Length;
- }
复制代码- #define REVERSE_BYTES_QUAD REVERSE_BYTES_8
- #define REVERSE_BYTES_8(Destination, Source) { \
- PEIGHT_BYTE d = (PEIGHT_BYTE)(Destination); \
- PEIGHT_BYTE s = (PEIGHT_BYTE)(Source); \
- d->Byte7 = s->Byte0; \
- d->Byte6 = s->Byte1; \
- d->Byte5 = s->Byte2; \
- d->Byte4 = s->Byte3; \
- d->Byte3 = s->Byte4; \
- d->Byte2 = s->Byte5; \
- d->Byte1 = s->Byte6; \
- d->Byte0 = s->Byte7; \
- }
复制代码- //------------------------------------------------------------------------------
- // read / write physical disk
- //------------------------------------------------------------------------------
- NTSTATUS ReadWritePhysicalDisk(PDEVICE_OBJECT DeviceObject,PFILE_OBJECT FileObject,ULONG MajorFunction,PVOID buffer,ULONG length,PLARGE_INTEGER offset)
- {
- KEVENT Event;
- PIRP Irp;
- IO_STATUS_BLOCK IoStatusBlock;
- PIO_STACK_LOCATION Stack;
- NTSTATUS Status;
- // initialize notification event object
- KeInitializeEvent(&Event,NotificationEvent,FALSE);
- // allocate and set up an IRP for a synchronously processed I/O request
- Irp = IoBuildSynchronousFsdRequest(MajorFunction,DeviceObject,buffer,length,offset,&Event,&IoStatusBlock);
- if(Irp == NULL)
- {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- // get higher level driver access to the next lower driver's I/O stack location
- Stack = IoGetNextIrpStackLocation(Irp);
- // set the flag SL_OVERRIDE_VERIFY_VOLUME
- Stack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
- // since Windows Vista direct write operations to volumes and disks are blocked, therefore we use the flag SL_FORCE_DIRECT_WRITE
- // which bypasses the check in file system and storage drivers
- if(MajorFunction == IRP_MJ_WRITE)
- {
- // set the flag SL_FORCE_DIRECT_WRITE
- Stack->Flags |= SL_FORCE_DIRECT_WRITE;
- }
- // reference file object, we take an extra reference here to prevent early unload problems
- ObReferenceObject(FileObject);
- // set the FileObject pointer in the first stack location
- Stack->FileObject = FileObject;
- // send IRP to the device object
- Status = IoCallDriver(DeviceObject,Irp);
- if(Status == STATUS_PENDING)
- {
- // wait for disk read / write to finish
- KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
- // get returned NTSTATUS value
- Status = IoStatusBlock.Status;
- }
- // dereference file object
- ObDereferenceObject(FileObject);
- return Status;
- }
复制代码
|
|