前段时间,只需用一台新电脑,由于资金有限没有匹配了心仪已久的SSD。我没感觉到飞翔的感觉,总不甘心,仔细想想。我死了相当大的存储,我们可以假设部分内存作为硬盘驱动器把它弄出来。不会比固态硬盘的速度快,我们開始吧。
首先。我们要做的就是写一个硬盘控制器的驱动,我们知道。存储类型的驱动一般都遵守 class/port/miniport driver 这种结构。微软已经完毕了磁盘类的驱动,以及 SCSI 总线的 Port 驱动,我们仅仅须要完毕 SCSI 总线上硬盘控制器的 Miniport 驱动就能够了。
拿出 DDK 的源代码分析一遍,微软果然不负众望地提供了一个驱动的源代码,我用的是DDK 7600.16385.1,里面有一个 ramdisk 的源代码,但读起来就发现。它是用 wdf 框架来实现的。我对 wdf 框架不熟悉。决定自己用 wdm 框架来又一次实现一遍。
接着便是各种资料的查询。最后最终摸清了SCSI miniport 驱动的大体框架。为了给一个极致简单的框架。我省去了很多冗余的代码,代码例如以下:
#define DBG 1 #include <ntddk.h> #include <srb.h> #include <scsi.h> #define MODULE_NAME_PREFIX "RamDisk: " #define KdPrintThisFunction() KdPrint((MODULE_NAME_PREFIX"%s\n", __FUNCTION__)) #define RAMDISK_SECTOR_SIZE 512 #define RAMDISK_CAPACITY 16 * 1024 *1024 //typedef struct _DEVICE_EXTENSION { //} DEVICE_EXTENSION, *PDEVICE_EXTENSION; // Miniport 的一些回调函数 BOOLEAN Initialize(__in PVOID DeviceExtension); BOOLEAN ResetBus(__in PVOID DeviceExtension, __in ULONG PathId); BOOLEAN StartIo(__in PVOID DeviceExtension, __in PSCSI_REQUEST_BLOCK Srb); BOOLEAN Interrupt(__in PVOID DeviceExtension); ULONG FindAdapter( __in PVOID DeviceExtension, __in PVOID HwContext, __in PVOID BusInformation, __in PCHAR ArgumentString, __inout PPORT_CONFIGURATION_INFORMATION ConfigInfo, __out PBOOLEAN Again ); BOOLEAN AdapterState(__in PVOID DeviceExtension, __in PVOID Context, __in BOOLEAN SaveState); SCSI_ADAPTER_CONTROL_STATUS AdapterControl(PVOID DeviceExtension,SCSI_ADAPTER_CONTROL_TYPE ctlType,PVOID pParameters); VOID DriverUnload(__in struct _DRIVER_OBJECT *DriverObject); PVOID RamDiskMemroy; NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT *DriverObject, __in PUNICODE_STRING RegistryPath ) { HW_INITIALIZATION_DATA HwInitData; KdPrintThisFunction(); RtlZeroMemory(&HwInitData, sizeof(HW_INITIALIZATION_DATA)); HwInitData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA); HwInitData.HwInitialize = Initialize; HwInitData.HwResetBus = ResetBus; HwInitData.HwStartIo = StartIo; HwInitData.HwInterrupt = NULL; // 不须要中断服务 HwInitData.HwFindAdapter = FindAdapter; HwInitData.HwAdapterState = AdapterState; HwInitData.HwAdapterControl = AdapterControl; HwInitData.AdapterInterfaceType = Isa; HwInitData.DeviceExtensionSize = 0; HwInitData.SrbExtensionSize = 0; HwInitData.NumberOfAccessRanges = 0; HwInitData.MapBuffers = TRUE; HwInitData.NeedPhysicalAddresses = FALSE; HwInitData.TaggedQueuing = FALSE; HwInitData.AutoRequestSense = TRUE; HwInitData.MultipleRequestPerLu = FALSE; HwInitData.ReceiveEvent = FALSE; // 初始化 ScsiPortInitialize(DriverObject, RegistryPath, &HwInitData, NULL); DriverObject->DriverUnload = DriverUnload; RamDiskMemroy = ExAllocatePool(NonPagedPool, RAMDISK_CAPACITY); if (RamDiskMemroy == NULL) { KdPrint(("RamDisk: Allocate memory failed!\n")); return STATUS_FAILED_DRIVER_ENTRY; } KdPrint(("MyRamDisk: RamDiskMemroy - 0x%p\n", RamDiskMemroy)); return STATUS_SUCCESS; } VOID DriverUnload( __in struct _DRIVER_OBJECT *DriverObject ) { KdPrintThisFunction(); ExFreePool(RamDiskMemroy); } BOOLEAN Initialize( __in PVOID DeviceExtension ) { KdPrintThisFunction(); return TRUE; } BOOLEAN ResetBus( __in PVOID DeviceExtension, __in ULONG PathId ) { KdPrintThisFunction(); return TRUE; } BOOLEAN ReadCapacityData( PSCSI_REQUEST_BLOCK Srb ) { PREAD_CAPACITY_DATA CapacityData = (PREAD_CAPACITY_DATA)Srb->DataBuffer; ULONG Value = 0; KdPrintThisFunction(); // this two value should in Big Endian Value = RAMDISK_CAPACITY / RAMDISK_SECTOR_SIZE - 1; REVERSE_LONG(&Value); CapacityData->LogicalBlockAddress = Value; Value = RAMDISK_SECTOR_SIZE; REVERSE_LONG(&Value); CapacityData->BytesPerBlock = Value; return TRUE; } BOOLEAN Inquiry( PSCSI_REQUEST_BLOCK Srb ) { PINQUIRYDATA InquiryData = (PINQUIRYDATA)Srb->DataBuffer; PCDB Cdb = &Srb->Cdb; KdPrintThisFunction(); InquiryData->DeviceType = DIRECT_ACCESS_DEVICE; InquiryData->DeviceTypeQualifier = DEVICE_CONNECTED; InquiryData->DeviceTypeModifier = 0; InquiryData->RemovableMedia = 0; InquiryData->ResponseDataFormat = 2; InquiryData->Versions = 0; InquiryData->AdditionalLength = sizeof(INQUIRYDATA) - 5; // 这些数据关系到系统中设备管理器的显示 RtlMoveMemory(InquiryData->VendorId,"HENZOX",6); RtlMoveMemory(InquiryData->ProductId,"RamDisk - Henzox",16); RtlMoveMemory(InquiryData->ProductRevisionLevel,"1010",4); KdPrint(("Inquiry: succeeded(target-lun)=(%d,%d)\n", Srb->TargetId, Srb->Lun)); return TRUE; } BOOLEAN ReadDisk( PSCSI_REQUEST_BLOCK Srb ) { ULONG Start = 0; // 開始扇区 USHORT Count = 0; // 读取大小,以扇区为单位 PCDB Cdb = &Srb->Cdb[0]; Start = *(PULONG)&Cdb->CDB10.LogicalBlockByte0; REVERSE_LONG(&Start); Count = *(PUSHORT)&Cdb->CDB10.TransferBlocksMsb; REVERSE_SHORT(&Count); if ((Start + Count) * RAMDISK_SECTOR_SIZE > RAMDISK_CAPACITY) { KdPrint(("ReadDisk: overflow!\n")); return FALSE; } // Count * RAMDISK_SECTOR_SIZE equals to Srb->DataTransferLength KdPrint(("ReadDisk: Start - %d, Size - %d\n", Start * RAMDISK_SECTOR_SIZE, Srb->DataTransferLength)); RtlMoveMemory(Srb->DataBuffer, (PUCHAR)RamDiskMemroy + Start * RAMDISK_SECTOR_SIZE, Srb->DataTransferLength); return TRUE; } BOOLEAN WriteDisk( PSCSI_REQUEST_BLOCK Srb ) { ULONG Start = 0; // 開始地址 USHORT Count = 0; // 读取大小,以扇区为单位 PCDB Cdb = &Srb->Cdb[0]; Start = *(PULONG)&Cdb->CDB10.LogicalBlockByte0; REVERSE_LONG(&Start); Count = *(PUSHORT)&Cdb->CDB10.TransferBlocksMsb; REVERSE_SHORT(&Count); if (Start + Count * RAMDISK_SECTOR_SIZE > RAMDISK_CAPACITY) { KdPrint(("WriteDisk: overflow!\n")); return FALSE; } KdPrint(("WriteDisk: Start - %d, Size - %d\n", Start * RAMDISK_SECTOR_SIZE, Srb->DataTransferLength)); RtlMoveMemory((PUCHAR)RamDiskMemroy + Start * RAMDISK_SECTOR_SIZE, Srb->DataBuffer, Srb->DataTransferLength); return TRUE; } BOOLEAN ExecuteScsi( PSCSI_REQUEST_BLOCK Srb ) { BOOLEAN ReturnValue = FALSE; PCDB Cdb = (PCDB)&Srb->Cdb[0]; KdPrintThisFunction(); switch (Cdb->CDB10.OperationCode) { case 0x28: // Read disk ReturnValue = ReadDisk(Srb); break; case 0x2A: // Write disk ReturnValue = WriteDisk(Srb); break; case 0x25: // Read the capacity of the disk ReturnValue = ReadCapacityData(Srb); break; case 0x12: // Disk inquiry ReturnValue = Inquiry(Srb); break; default: KdPrint(("ExecuteScsi: Unknown operation code(0x%p)\n", Cdb->CDB10.OperationCode)); ReturnValue = TRUE; } return ReturnValue; } BOOLEAN DoIoControl( PSCSI_REQUEST_BLOCK Srb ) { KdPrintThisFunction(); return TRUE; } BOOLEAN StartIo( __in PVOID DeviceExtension, __in PSCSI_REQUEST_BLOCK Srb ) { BOOLEAN ReturnValue = TRUE; KdPrintThisFunction(); Srb->SrbStatus = SRB_STATUS_SUCCESS; Srb->ScsiStatus = SCSISTAT_GOOD; switch(Srb->Function) { case SRB_FUNCTION_SHUTDOWN: KdPrint(("StartIo: SRB_FUNCTION_SHUTDOWN\n")); break; case SRB_FUNCTION_FLUSH: KdPrint(("StartIo: SRB_FUNCTION_FLUSH\n")); break; case SRB_FUNCTION_EXECUTE_SCSI: // 运行 SCSI 命令 ReturnValue = ExecuteScsi(Srb); break; case SRB_FUNCTION_IO_CONTROL: Srb->SrbStatus = SRB_STATUS_PENDING; ReturnValue = DoIoControl(Srb); break; default: Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; } ScsiPortNotification(RequestComplete, DeviceExtension, Srb); ScsiPortNotification(NextRequest, DeviceExtension); return ReturnValue; } BOOLEAN Interrupt( __in PVOID DeviceExtension ) { KdPrintThisFunction(); return TRUE; } ULONG FindAdapter( __in PVOID DeviceExtension, __in PVOID HwContext, __in PVOID BusInformation, __in PCHAR ArgumentString, __inout PPORT_CONFIGURATION_INFORMATION ConfigInfo, __out PBOOLEAN Again ) { KdPrintThisFunction(); ConfigInfo->AdapterInterfaceType = Isa; ConfigInfo->AlignmentMask = 0x00000003; ConfigInfo->AutoRequestSense = TRUE; ConfigInfo->BufferAccessScsiPortControlled = FALSE; ConfigInfo->BusInterruptLevel = 0; ConfigInfo->BusInterruptVector = 0; ConfigInfo->Dma32BitAddresses = TRUE; ConfigInfo->Master = TRUE; ConfigInfo->CachesData = TRUE; ConfigInfo->NumberOfBuses = 1; ConfigInfo->MaximumNumberOfTargets = 1; ConfigInfo->MaximumTransferLength = 0x10000; ConfigInfo->MultipleRequestPerLu = FALSE; ConfigInfo->NumberOfPhysicalBreaks = 0x00F8; ConfigInfo->ScatterGather = TRUE; ConfigInfo->TaggedQueuing = FALSE; *Again = FALSE; return SP_RETURN_FOUND; } SCSI_ADAPTER_CONTROL_STATUS AdapterControl( PVOID DeviceExtension, SCSI_ADAPTER_CONTROL_TYPE CtlType, PVOID Parameters ) { PSCSI_SUPPORTED_CONTROL_TYPE_LIST ScsiList=NULL; SCSI_ADAPTER_CONTROL_STATUS status = ScsiAdapterControlSuccess; KdPrintThisFunction(); switch (CtlType<span style="font-family: Arial, Helvetica, sans-serif;">) </span>{ case ScsiQuerySupportedControlTypes: KdPrint(("AdapterControl: ScsiQuerySupportedControlTypes\n")); ScsiList = (PSCSI_SUPPORTED_CONTROL_TYPE_LIST)Parameters; <span style="font-family: Arial, Helvetica, sans-serif;">ScsiList</span>->SupportedTypeList[ScsiStopAdapter] = TRUE; ScsiList->SupportedTypeList[ScsiRestartAdapter] = TRUE; ScsiList->SupportedTypeList[ScsiQuerySupportedControlTypes] = TRUE; break; case ScsiStopAdapter: KdPrint(("AdapterControl: ScsiStopAdapter\n")); break; case ScsiRestartAdapter: KdPrint(("AdapterControl: ScsiRestartAdapter\n")); break; default: status = ScsiAdapterControlUnsuccessful; break; } return status; } BOOLEAN AdapterState( __in PVOID DeviceExtension, __in PVOID Context, __in BOOLEAN SaveState ) { KdPrintThisFunction(); return TRUE; }
简要地说明一下。Scsiminiport 驱动事实上非常easy,就是调用ScsiPortInitialize 初始化之后,完毕各种 Srb 命令就能够了,源代码中本来想用中文凝视和英文凝视混杂。这是我的一个不好习惯,但凝视明了。极易读懂。
编译出来之后。能够直接安装。然后在磁盘管理里会新出现一个磁盘。初始化这个磁盘就能够了,我只设了 16M 以用来实现,能够通过改动源代码达到你想要的大小。把它用来当浏览器的暂时文件夹存储盘是相当不错的。每次重新启动,该盘会销毁,在微软的 wdf 源代码中有怎样使该盘自己主动初始化的源代码。你也能够加入一些其他功能,比方关机时把该盘中的功能 dump 到一个文件中,设备重新启动后再载入。就可以达到固化的效果。事实上网上有许多的成熟的产品能够使用,自己写一个也不过为了练习而已,驱动没有经过大量測试,这可能会导致蓝屏,而且它也可以在虚拟机上更改。
版权声明:本文博客原创文章,博客,未经同意,不得转载。