2 * PROJECT: Ramdisk Class Driver
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/storage/class/ramdisk/ramdisk.c
5 * PURPOSE: Main Driver Routines
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
25 #include <reactos/drivers/ntddrdsk.h>
26 #include "../../../filesystems/fs_rec/fs_rec.h"
31 #define DO_XIP 0x00020000
33 /* GLOBALS ********************************************************************/
35 #define RAMDISK_SESSION_SIZE \
36 FIELD_OFFSET(CDROM_TOC, TrackData) + sizeof(TRACK_DATA)
38 #define RAMDISK_TOC_SIZE \
39 FIELD_OFFSET(CDROM_TOC, TrackData) + 2 * sizeof(TRACK_DATA)
41 #define TOC_DATA_TRACK (0x04)
43 typedef enum _RAMDISK_DEVICE_TYPE
47 } RAMDISK_DEVICE_TYPE
;
49 typedef enum _RAMDISK_DEVICE_STATE
51 RamdiskStateUninitialized
,
56 RamdiskStateBusRemoved
,
57 RamdiskStateEnumerated
,
58 } RAMDISK_DEVICE_STATE
;
60 DEFINE_GUID(RamdiskBusInterface
,
64 0x80, 0xE4, 0x05, 0xF8, 0x10, 0xE7, 0xA8, 0x8A);
66 typedef struct _RAMDISK_EXTENSION
68 RAMDISK_DEVICE_TYPE Type
;
69 RAMDISK_DEVICE_STATE State
;
70 PDEVICE_OBJECT DeviceObject
;
71 PDEVICE_OBJECT PhysicalDeviceObject
;
72 PDEVICE_OBJECT AttachedDevice
;
73 IO_REMOVE_LOCK RemoveLock
;
74 UNICODE_STRING DriveDeviceName
;
75 UNICODE_STRING BusDeviceName
;
76 FAST_MUTEX DiskListLock
;
78 } RAMDISK_EXTENSION
, *PRAMDISK_EXTENSION
;
80 typedef struct _RAMDISK_BUS_EXTENSION
83 } RAMDISK_BUS_EXTENSION
, *PRAMDISK_BUS_EXTENSION
;
85 typedef struct _RAMDISK_DRIVE_EXTENSION
88 // Inherited base class
93 // Data we get from the creator
96 UNICODE_STRING GuidString
;
97 UNICODE_STRING SymbolicLinkName
;
99 RAMDISK_CREATE_OPTIONS DiskOptions
;
100 LARGE_INTEGER DiskLength
;
106 // Data we get from the disk
108 ULONG BytesPerSector
;
109 ULONG SectorsPerTrack
;
113 } RAMDISK_DRIVE_EXTENSION
, *PRAMDISK_DRIVE_EXTENSION
;
115 ULONG MaximumViewLength
;
116 ULONG MaximumPerDiskViewLength
;
117 ULONG ReportDetectedDevice
;
118 ULONG MarkRamdisksAsRemovable
;
119 ULONG MinimumViewCount
;
120 ULONG DefaultViewCount
;
121 ULONG MaximumViewCount
;
122 ULONG MinimumViewLength
;
123 ULONG DefaultViewLength
;
124 UNICODE_STRING DriverRegistryPath
;
125 BOOLEAN ExportBootDiskAsCd
;
127 PDEVICE_OBJECT RamdiskBusFdo
;
129 /* FUNCTIONS ******************************************************************/
133 QueryParameters(IN PUNICODE_STRING RegistryPath
)
135 ULONG MinView
, DefView
, MinViewLength
, DefViewLength
, MaxViewLength
;
136 RTL_QUERY_REGISTRY_TABLE QueryTable
[10];
141 MaximumViewLength
= 0x10000000u
;
142 MaximumPerDiskViewLength
= 0x10000000u
;
143 ReportDetectedDevice
= 0;
144 MarkRamdisksAsRemovable
= 0;
145 MinimumViewCount
= 2;
146 DefaultViewCount
= 16;
147 MaximumViewCount
= 64;
148 MinimumViewLength
= 0x10000u
;
149 DefaultViewLength
= 0x100000u
;
152 // Setup the query table and query the registry
154 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
155 QueryTable
[0].Flags
= 1;
156 QueryTable
[0].Name
= L
"Parameters";
157 QueryTable
[1].Flags
= 32;
158 QueryTable
[1].Name
= L
"ReportDetectedDevice";
159 QueryTable
[1].EntryContext
= &ReportDetectedDevice
;
160 QueryTable
[2].Flags
= 32;
161 QueryTable
[2].Name
= L
"MarkRamdisksAsRemovable";
162 QueryTable
[2].EntryContext
= &MarkRamdisksAsRemovable
;
163 QueryTable
[3].Flags
= 32;
164 QueryTable
[3].Name
= L
"MinimumViewCount";
165 QueryTable
[3].EntryContext
= &MinimumViewCount
;
166 QueryTable
[4].Flags
= 32;
167 QueryTable
[4].Name
= L
"DefaultViewCount";
168 QueryTable
[4].EntryContext
= &DefaultViewCount
;
169 QueryTable
[5].Flags
= 32;
170 QueryTable
[5].Name
= L
"MaximumViewCount";
171 QueryTable
[5].EntryContext
= &MaximumViewCount
;
172 QueryTable
[6].Flags
= 32;
173 QueryTable
[6].Name
= L
"MinimumViewLength";
174 QueryTable
[6].EntryContext
= &MinimumViewLength
;
175 QueryTable
[7].Flags
= 32;
176 QueryTable
[7].Name
= L
"DefaultViewLength";
177 QueryTable
[7].EntryContext
= &DefaultViewLength
;
178 QueryTable
[8].Flags
= 32;
179 QueryTable
[8].Name
= L
"MaximumViewLength";
180 QueryTable
[8].EntryContext
= &MaximumViewLength
;
181 QueryTable
[9].Flags
= 32;
182 QueryTable
[9].Name
= L
"MaximumPerDiskViewLength";
183 QueryTable
[9].EntryContext
= &MaximumPerDiskViewLength
;
184 RtlQueryRegistryValues(RTL_REGISTRY_OPTIONAL
,
185 RegistryPath
->Buffer
,
191 // Parse minimum view count, cannot be bigger than 256 or smaller than 2
193 MinView
= MinimumViewCount
;
194 if (MinimumViewCount
>= 2)
196 if (MinimumViewCount
> 256) MinView
= 256;
202 MinimumViewCount
= MinView
;
205 // Parse default view count, cannot be bigger than 256 or smaller than minimum
207 DefView
= DefaultViewCount
;
208 if (DefaultViewCount
>= MinView
)
210 if (DefaultViewCount
> 256) DefView
= 256;
216 DefaultViewCount
= DefView
;
219 // Parse maximum view count, cannot be bigger than 256 or smaller than default
221 if (MaximumViewCount
>= DefView
)
223 if (MaximumViewCount
> 256) MaximumViewCount
= 256;
227 MaximumViewCount
= DefView
;
231 // Parse minimum view length, cannot be bigger than 1GB or smaller than 64KB
233 MinViewLength
= MinimumViewLength
;
234 if (MinimumViewLength
>= 0x10000)
236 if (MinimumViewLength
> 0x40000000) MinViewLength
= 0x40000000u
;
240 MinViewLength
= 0x10000u
;
242 MinimumViewLength
= MinViewLength
;
245 // Parse default view length, cannot be bigger than 1GB or smaller than minimum
247 DefViewLength
= DefaultViewLength
;
248 if (DefaultViewLength
>= MinViewLength
)
250 if (DefaultViewLength
> 0x40000000) DefViewLength
= 0x40000000u
;
254 DefViewLength
= MinViewLength
;
256 DefaultViewLength
= DefViewLength
;
259 // Parse maximum view length, cannot be bigger than 1GB or smaller than default
261 MaxViewLength
= MaximumViewLength
;
262 if (MaximumViewLength
>= DefViewLength
)
264 if (MaximumViewLength
> 0x40000000) MaxViewLength
= 0x40000000u
;
268 MaxViewLength
= DefViewLength
;
270 MaximumViewLength
= MaxViewLength
;
273 // Parse maximum view length per disk, cannot be smaller than 16MB
275 if (MaximumPerDiskViewLength
>= 0x1000000)
277 if (MaxViewLength
> 0xFFFFFFFF) MaximumPerDiskViewLength
= -1;
281 MaximumPerDiskViewLength
= 0x1000000u
;
287 RamdiskMapPages(IN PRAMDISK_DRIVE_EXTENSION DeviceExtension
,
288 IN LARGE_INTEGER Offset
,
290 OUT PULONG OutputLength
)
292 PHYSICAL_ADDRESS PhysicalAddress
;
296 LARGE_INTEGER ActualOffset
;
297 LARGE_INTEGER ActualPages
;
300 // We only support boot disks for now
302 ASSERT(DeviceExtension
->DiskType
== RAMDISK_BOOT_DISK
);
305 // Calculate the actual offset in the drive
307 ActualOffset
.QuadPart
= DeviceExtension
->DiskOffset
+ Offset
.QuadPart
;
312 ActualPages
.QuadPart
= ActualOffset
.QuadPart
>> PAGE_SHIFT
;
315 // Now add the base page
317 ActualPages
.QuadPart
= DeviceExtension
->BasePage
+ ActualPages
.QuadPart
;
320 // Calculate final amount of bytes
322 PhysicalAddress
.QuadPart
= ActualPages
.QuadPart
<< PAGE_SHIFT
;
325 // Calculate pages spanned for the mapping
327 ActualLength
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(ActualOffset
.QuadPart
, Length
);
330 // And convert this back to bytes
332 ActualLength
<<= PAGE_SHIFT
;
335 // Get the offset within the page
337 PageOffset
= BYTE_OFFSET(ActualOffset
.QuadPart
);
340 // Map the I/O Space from the loader
342 MappedBase
= MmMapIoSpace(PhysicalAddress
, ActualLength
, MmCached
);
345 // Return actual offset within the page as well as the length
347 if (MappedBase
) MappedBase
= (PVOID
)((ULONG_PTR
)MappedBase
+ PageOffset
);
348 *OutputLength
= Length
;
354 RamdiskUnmapPages(IN PRAMDISK_DRIVE_EXTENSION DeviceExtension
,
355 IN PVOID BaseAddress
,
356 IN LARGE_INTEGER Offset
,
359 LARGE_INTEGER ActualOffset
;
364 // We only support boot disks for now
366 ASSERT(DeviceExtension
->DiskType
== RAMDISK_BOOT_DISK
);
369 // Calculate the actual offset in the drive
371 ActualOffset
.QuadPart
= DeviceExtension
->DiskOffset
+ Offset
.QuadPart
;
374 // Calculate pages spanned for the mapping
376 ActualLength
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(ActualOffset
.QuadPart
, Length
);
379 // And convert this back to bytes
381 ActualLength
<<= PAGE_SHIFT
;
384 // Get the offset within the page
386 PageOffset
= BYTE_OFFSET(ActualOffset
.QuadPart
);
389 // Calculate actual base address where we mapped this
391 BaseAddress
= (PVOID
)((ULONG_PTR
)BaseAddress
- PageOffset
);
394 // Unmap the I/O space we got from the loader
396 MmUnmapIoSpace(BaseAddress
, ActualLength
);
401 RamdiskCreateDiskDevice(IN PRAMDISK_BUS_EXTENSION DeviceExtension
,
402 IN PRAMDISK_CREATE_INPUT Input
,
403 IN BOOLEAN ValidateOnly
,
404 OUT PRAMDISK_DRIVE_EXTENSION
*NewDriveExtension
)
406 ULONG BasePage
, DiskType
, Length
;
409 PDEVICE_OBJECT DeviceObject
;
410 PRAMDISK_DRIVE_EXTENSION DriveExtension
;
412 WCHAR LocalBuffer
[16];
413 UNICODE_STRING SymbolicLinkName
, DriveString
, GuidString
, DeviceName
;
414 PPACKED_BOOT_SECTOR BootSector
;
415 BIOS_PARAMETER_BLOCK BiosBlock
;
416 ULONG BytesPerSector
, SectorsPerTrack
, Heads
, BytesRead
;
418 LARGE_INTEGER CurrentOffset
, CylinderSize
, DiskLength
;
419 ULONG CylinderCount
, SizeByCylinders
;
422 // Check if we're a boot RAM disk
424 DiskType
= Input
->DiskType
;
425 if (DiskType
>= RAMDISK_BOOT_DISK
)
428 // Check if we're an ISO
430 if (DiskType
== RAMDISK_BOOT_DISK
)
433 // NTLDR mounted us somewhere
435 BasePage
= Input
->BasePage
;
436 if (!BasePage
) return STATUS_INVALID_PARAMETER
;
439 // Sanitize disk options
441 Input
->Options
.Fixed
= TRUE
;
442 Input
->Options
.Readonly
= Input
->Options
.ExportAsCd
|
443 Input
->Options
.Readonly
;
444 Input
->Options
.Hidden
= FALSE
;
445 Input
->Options
.NoDosDevice
= FALSE
;
446 Input
->Options
.NoDriveLetter
= IsWinPEBoot
? TRUE
: FALSE
;
451 // The only other possibility is a WIM disk
453 if (DiskType
!= RAMDISK_WIM_DISK
)
458 return STATUS_INVALID_PARAMETER
;
462 // Read the view count instead
464 //ViewCount = Input->ViewCount;
467 // Sanitize disk options
469 Input
->Options
.Hidden
= FALSE
;
470 Input
->Options
.NoDosDevice
= FALSE
;
471 Input
->Options
.Readonly
= FALSE
;
472 Input
->Options
.NoDriveLetter
= TRUE
;
473 Input
->Options
.Fixed
= TRUE
;
477 // Are we just validating and returning to the user?
479 if (ValidateOnly
) return STATUS_SUCCESS
;
482 // Build the GUID string
484 Status
= RtlStringFromGUID(&Input
->DiskGuid
, &GuidString
);
485 if (!(NT_SUCCESS(Status
)) || !(GuidString
.Buffer
))
490 Status
= STATUS_INSUFFICIENT_RESOURCES
;
495 // Allocate our device name
497 Length
= GuidString
.Length
+ 32;
498 Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
506 Status
= STATUS_INSUFFICIENT_RESOURCES
;
511 // Build the device name string
513 DeviceName
.Buffer
= Buffer
;
514 DeviceName
.Length
= Length
- 2;
515 DeviceName
.MaximumLength
= Length
;
516 wcsncpy(Buffer
, L
"\\Device\\Ramdisk", Length
/ sizeof(WCHAR
));
517 wcsncat(Buffer
, GuidString
.Buffer
, Length
/ sizeof(WCHAR
));
520 // Create the drive device
522 Status
= IoCreateDevice(DeviceExtension
->DeviceObject
->DriverObject
,
523 sizeof(RAMDISK_DRIVE_EXTENSION
),
525 (Input
->Options
.ExportAsCd
) ?
526 FILE_DEVICE_CD_ROM
: FILE_DEVICE_DISK
,
530 if (!NT_SUCCESS(Status
)) goto FailCreate
;
533 // Grab the drive extension
535 DriveExtension
= DeviceObject
->DeviceExtension
;
538 // Check if we need a DOS device
540 if (!Input
->Options
.NoDosDevice
)
543 // Build the symbolic link name
545 SymbolicLinkName
.MaximumLength
= GuidString
.Length
+ 36;
546 SymbolicLinkName
.Length
= GuidString
.Length
+ 34;
547 Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
548 SymbolicLinkName
.MaximumLength
,
550 SymbolicLinkName
.Buffer
= Buffer
;
557 L
"\\GLOBAL??\\Ramdisk",
558 SymbolicLinkName
.MaximumLength
/ sizeof(WCHAR
));
561 SymbolicLinkName
.MaximumLength
/ sizeof(WCHAR
));
562 Status
= IoCreateSymbolicLink(&SymbolicLinkName
, &DeviceName
);
563 if (!NT_SUCCESS(Status
))
568 Input
->Options
.NoDosDevice
= TRUE
;
570 SymbolicLinkName
.Buffer
= NULL
;
578 Input
->Options
.NoDosDevice
= TRUE
;
582 // It this an ISO boot ramdisk?
584 if (Input
->DiskType
== RAMDISK_BOOT_DISK
)
587 // Does it need a drive letter?
589 if (!Input
->Options
.NoDriveLetter
)
592 // Build it and take over the existing symbolic link
594 _snwprintf(LocalBuffer
,
596 L
"\\DosDevices\\%wc:",
598 RtlInitUnicodeString(&DriveString
, LocalBuffer
);
599 IoDeleteSymbolicLink(&DriveString
);
600 IoCreateSymbolicLink(&DriveString
, &DeviceName
);
603 // Save the drive letter
605 DriveExtension
->DriveLetter
= Input
->DriveLetter
;
612 // Setup the device object flags
614 DeviceObject
->Flags
|= (DO_XIP
| DO_POWER_PAGABLE
| DO_DIRECT_IO
);
615 DeviceObject
->AlignmentRequirement
= 1;
618 // Build the drive FDO
620 *NewDriveExtension
= DriveExtension
;
621 DriveExtension
->Type
= RamdiskDrive
;
622 DiskLength
= Input
->DiskLength
;
623 ExInitializeFastMutex(&DriveExtension
->DiskListLock
);
624 IoInitializeRemoveLock(&DriveExtension
->RemoveLock
,
628 DriveExtension
->DriveDeviceName
= DeviceName
;
629 DriveExtension
->SymbolicLinkName
= SymbolicLinkName
;
630 DriveExtension
->GuidString
= GuidString
;
631 DriveExtension
->DiskGuid
= Input
->DiskGuid
;
632 DriveExtension
->PhysicalDeviceObject
= DeviceObject
;
633 DriveExtension
->DeviceObject
= RamdiskBusFdo
;
634 DriveExtension
->AttachedDevice
= RamdiskBusFdo
;
635 DriveExtension
->DiskType
= Input
->DiskType
;
636 DriveExtension
->DiskOptions
= Input
->Options
;
637 DriveExtension
->DiskLength
= DiskLength
;
638 DriveExtension
->DiskOffset
= Input
->DiskOffset
;
639 DriveExtension
->BasePage
= Input
->BasePage
;
640 DriveExtension
->BytesPerSector
= 0;
641 DriveExtension
->SectorsPerTrack
= 0;
642 DriveExtension
->NumberOfHeads
= 0;
645 // Make sure we don't free it later
647 DeviceName
.Buffer
= NULL
;
648 SymbolicLinkName
.Buffer
= NULL
;
649 GuidString
.Buffer
= NULL
;
652 // Check if this is an boot disk, or a registry ram drive
654 if (!(Input
->Options
.ExportAsCd
) &&
655 (Input
->DiskType
== RAMDISK_BOOT_DISK
))
658 // Not an ISO boot, but it's a boot FS -- map it to figure out the
661 CurrentOffset
.QuadPart
= 0;
662 BaseAddress
= RamdiskMapPages(DriveExtension
,
671 BootSector
= (PPACKED_BOOT_SECTOR
)BaseAddress
;
672 FatUnpackBios(&BiosBlock
, &BootSector
->PackedBpb
);
673 BytesPerSector
= BiosBlock
.BytesPerSector
;
674 SectorsPerTrack
= BiosBlock
.SectorsPerTrack
;
675 Heads
= BiosBlock
.Heads
;
680 DriveExtension
->BytesPerSector
= BytesPerSector
;
681 DriveExtension
->SectorsPerTrack
= SectorsPerTrack
;
682 DriveExtension
->NumberOfHeads
= Heads
;
687 CurrentOffset
.QuadPart
= 0;
688 RamdiskUnmapPages(DriveExtension
,
698 Status
= STATUS_INSUFFICIENT_RESOURCES
;
704 // Check if the drive settings haven't been set yet
706 if ((DriveExtension
->BytesPerSector
== 0) ||
707 (DriveExtension
->SectorsPerTrack
== 0) ||
708 (DriveExtension
->NumberOfHeads
== 0))
711 // Check if this is a CD
713 if (Input
->Options
.ExportAsCd
)
716 // Setup partition parameters default for ISO 9660
718 DriveExtension
->BytesPerSector
= 2048;
719 DriveExtension
->SectorsPerTrack
= 32;
720 DriveExtension
->NumberOfHeads
= 64;
725 // Setup partition parameters default for FAT
727 DriveExtension
->BytesPerSector
= 512;
728 DriveExtension
->SectorsPerTrack
= 128;
729 DriveExtension
->NumberOfHeads
= 16;
734 // Calculate the cylinder size
736 CylinderSize
.QuadPart
= DriveExtension
->BytesPerSector
*
737 DriveExtension
->SectorsPerTrack
*
738 DriveExtension
->NumberOfHeads
;
739 CylinderCount
= DiskLength
.QuadPart
/ CylinderSize
.QuadPart
;
740 SizeByCylinders
= CylinderSize
.QuadPart
* CylinderCount
;
741 DriveExtension
->Cylinders
= CylinderCount
;
742 if ((DiskLength
.HighPart
> 0) || (SizeByCylinders
< DiskLength
.LowPart
))
745 // Align cylinder size up
747 DriveExtension
->Cylinders
++;
751 // Acquire the disk lock
753 KeEnterCriticalRegion();
754 ExAcquireFastMutex(&DeviceExtension
->DiskListLock
);
759 InsertTailList(&DeviceExtension
->DiskList
, &DriveExtension
->DiskList
);
764 ExReleaseFastMutex(&DeviceExtension
->DiskListLock
);
765 KeLeaveCriticalRegion();
770 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
771 return STATUS_SUCCESS
;
775 UNIMPLEMENTED_DBGBREAK();
776 return STATUS_SUCCESS
;
781 RamdiskCreateRamdisk(IN PDEVICE_OBJECT DeviceObject
,
783 IN BOOLEAN ValidateOnly
)
785 PRAMDISK_CREATE_INPUT Input
;
787 PRAMDISK_BUS_EXTENSION DeviceExtension
;
788 PRAMDISK_DRIVE_EXTENSION DriveExtension
;
790 PWCHAR FileNameStart
, FileNameEnd
;
792 PIO_STACK_LOCATION IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
795 // Get the device extension and our input data
797 DeviceExtension
= DeviceObject
->DeviceExtension
;
798 Length
= IoStackLocation
->Parameters
.DeviceIoControl
.InputBufferLength
;
799 Input
= (PRAMDISK_CREATE_INPUT
)Irp
->AssociatedIrp
.SystemBuffer
;
802 // Validate input parameters
804 if ((Length
< sizeof(RAMDISK_CREATE_INPUT
)) ||
805 (Input
->Version
!= sizeof(RAMDISK_CREATE_INPUT
)))
810 return STATUS_INVALID_PARAMETER
;
814 // Validate the disk type
816 DiskType
= Input
->DiskType
;
817 if (DiskType
== RAMDISK_WIM_DISK
) return STATUS_INVALID_PARAMETER
;
820 // Look at the disk type
822 if (DiskType
== RAMDISK_BOOT_DISK
)
825 // We only allow this as an early-init boot
827 if (!KeLoaderBlock
) return STATUS_INVALID_PARAMETER
;
830 // Save command-line flags
832 if (ExportBootDiskAsCd
) Input
->Options
.ExportAsCd
= TRUE
;
833 if (IsWinPEBoot
) Input
->Options
.NoDriveLetter
= TRUE
;
837 // Validate the disk type
839 if ((Input
->Options
.ExportAsCd
) && (DiskType
!= RAMDISK_BOOT_DISK
))
842 // If the type isn't CDFS, it has to at least be raw CD
844 if (DiskType
!= RAMDISK_MEMORY_MAPPED_DISK
) return STATUS_INVALID_PARAMETER
;
848 // Check if this is an actual file
850 if (DiskType
<= RAMDISK_MEMORY_MAPPED_DISK
)
853 // Validate the file name
855 FileNameStart
= (PWCHAR
)((ULONG_PTR
)Input
+ Length
);
856 FileNameEnd
= Input
->FileName
+ 1;
857 while ((FileNameEnd
< FileNameStart
) && *(FileNameEnd
)) FileNameEnd
++;
858 if (FileNameEnd
== FileNameStart
) return STATUS_INVALID_PARAMETER
;
862 // Create the actual device
864 Status
= RamdiskCreateDiskDevice(DeviceExtension
,
868 if (NT_SUCCESS(Status
))
871 // Invalidate and set success
873 IoInvalidateDeviceRelations(DeviceExtension
->PhysicalDeviceObject
, 0);
874 Irp
->IoStatus
.Information
= STATUS_SUCCESS
;
885 RamdiskGetPartitionInfo(IN PIRP Irp
,
886 IN PRAMDISK_DRIVE_EXTENSION DeviceExtension
)
889 PPARTITION_INFORMATION PartitionInfo
;
891 LARGE_INTEGER Zero
= {{0, 0}};
893 PIO_STACK_LOCATION IoStackLocation
;
896 // Validate the length
898 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
899 if (IoStackLocation
->Parameters
.DeviceIoControl
.
900 OutputBufferLength
< sizeof(PARTITION_INFORMATION
))
905 Status
= STATUS_BUFFER_TOO_SMALL
;
906 Irp
->IoStatus
.Status
= Status
;
907 Irp
->IoStatus
.Information
= 0;
912 // Map the partition table
914 BaseAddress
= RamdiskMapPages(DeviceExtension
, Zero
, PAGE_SIZE
, &Length
);
920 Status
= STATUS_INSUFFICIENT_RESOURCES
;
921 Irp
->IoStatus
.Status
= Status
;
922 Irp
->IoStatus
.Information
= 0;
927 // Fill out the information
929 PartitionInfo
= Irp
->AssociatedIrp
.SystemBuffer
;
930 PartitionInfo
->StartingOffset
.QuadPart
= DeviceExtension
->BytesPerSector
;
931 PartitionInfo
->PartitionLength
.QuadPart
= DeviceExtension
->BytesPerSector
*
932 DeviceExtension
->SectorsPerTrack
*
933 DeviceExtension
->NumberOfHeads
*
934 DeviceExtension
->Cylinders
;
935 PartitionInfo
->HiddenSectors
= DeviceExtension
->HiddenSectors
;
936 PartitionInfo
->PartitionNumber
= 0;
937 PartitionInfo
->PartitionType
= *((PCHAR
)BaseAddress
+ 450);
938 PartitionInfo
->BootIndicator
= (DeviceExtension
->DiskType
==
939 RAMDISK_BOOT_DISK
) ? TRUE
: FALSE
;
940 PartitionInfo
->RecognizedPartition
= IsRecognizedPartition(PartitionInfo
->
942 PartitionInfo
->RewritePartition
= FALSE
;
945 // Unmap the partition table
947 RamdiskUnmapPages(DeviceExtension
, BaseAddress
, Zero
, Length
);
952 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
953 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION
);
954 return STATUS_SUCCESS
;
959 RamdiskSetPartitionInfo(IN PIRP Irp
,
960 IN PRAMDISK_DRIVE_EXTENSION DeviceExtension
)
965 PIO_STACK_LOCATION Stack
;
966 LARGE_INTEGER Zero
= {{0, 0}};
967 PPARTITION_INFORMATION PartitionInfo
;
970 // First validate input
972 Stack
= IoGetCurrentIrpStackLocation(Irp
);
973 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(PARTITION_INFORMATION
))
975 Status
= STATUS_INVALID_PARAMETER
;
982 BaseAddress
= RamdiskMapPages(DeviceExtension
, Zero
, PAGE_SIZE
, &BytesRead
);
983 if (BaseAddress
== NULL
)
985 Status
= STATUS_INSUFFICIENT_RESOURCES
;
990 // Set the new partition type
991 // On partition 0, field system indicator
993 PartitionInfo
= (PPARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
994 *((PCHAR
)BaseAddress
+ 450) = PartitionInfo
->PartitionType
;
999 RamdiskUnmapPages(DeviceExtension
, BaseAddress
, Zero
, BytesRead
);
1000 Status
= STATUS_SUCCESS
;
1003 Irp
->IoStatus
.Status
= Status
;
1004 Irp
->IoStatus
.Information
= 0;
1010 RamdiskWorkerThread(IN PDEVICE_OBJECT DeviceObject
,
1013 PRAMDISK_BUS_EXTENSION DeviceExtension
;
1015 PIO_STACK_LOCATION IoStackLocation
;
1019 // Get the stack location
1021 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
1024 // Free the work item
1026 IoFreeWorkItem(Irp
->Tail
.Overlay
.DriverContext
[0]);
1029 // Grab the device extension and lock it
1031 DeviceExtension
= DeviceObject
->DeviceExtension
;
1032 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, Irp
);
1033 if (NT_SUCCESS(Status
))
1036 // Discriminate by major code
1038 switch (IoStackLocation
->MajorFunction
)
1043 case IRP_MJ_DEVICE_CONTROL
:
1046 // Let's take a look at the IOCTL
1048 switch (IoStackLocation
->Parameters
.DeviceIoControl
.IoControlCode
)
1051 // Ramdisk create request
1053 case FSCTL_CREATE_RAM_DISK
:
1056 // This time we'll do it for real
1058 Status
= RamdiskCreateRamdisk(DeviceObject
, Irp
, FALSE
);
1061 case IOCTL_DISK_SET_PARTITION_INFO
:
1063 Status
= RamdiskSetPartitionInfo(Irp
, (PRAMDISK_DRIVE_EXTENSION
)DeviceExtension
);
1066 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
1068 UNIMPLEMENTED_DBGBREAK("Get drive layout request\n");
1071 case IOCTL_DISK_GET_PARTITION_INFO
:
1073 Status
= RamdiskGetPartitionInfo(Irp
, (PRAMDISK_DRIVE_EXTENSION
)DeviceExtension
);
1078 UNIMPLEMENTED_DBGBREAK("Invalid request\n");
1088 // Read or write request
1093 UNIMPLEMENTED_DBGBREAK("Read/Write request\n");
1097 // Internal request (SCSI?)
1099 case IRP_MJ_INTERNAL_DEVICE_CONTROL
:
1101 UNIMPLEMENTED_DBGBREAK("SCSI request\n");
1107 case IRP_MJ_FLUSH_BUFFERS
:
1109 UNIMPLEMENTED_DBGBREAK("Flush request\n");
1117 UNIMPLEMENTED_DBGBREAK("Invalid request: %lx\n", IoStackLocation
->MajorFunction
);
1124 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, Irp
);
1125 Irp
->IoStatus
.Status
= Status
;
1126 Irp
->IoStatus
.Information
= 0;
1127 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1134 Irp
->IoStatus
.Status
= Status
;
1135 Irp
->IoStatus
.Information
= 0;
1136 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1141 SendIrpToThread(IN PDEVICE_OBJECT DeviceObject
,
1144 PIO_WORKITEM WorkItem
;
1147 // Mark the IRP pending
1149 IoMarkIrpPending(Irp
);
1152 // Allocate a work item
1154 WorkItem
= IoAllocateWorkItem(DeviceObject
);
1160 Irp
->Tail
.Overlay
.DriverContext
[0] = WorkItem
;
1161 IoQueueWorkItem(WorkItem
, RamdiskWorkerThread
, DelayedWorkQueue
, Irp
);
1162 return STATUS_PENDING
;
1169 return STATUS_INSUFFICIENT_RESOURCES
;
1175 RamdiskReadWriteReal(IN PIRP Irp
,
1176 IN PRAMDISK_DRIVE_EXTENSION DeviceExtension
)
1179 PVOID CurrentBase
, SystemVa
, BaseAddress
;
1180 PIO_STACK_LOCATION IoStackLocation
;
1181 LARGE_INTEGER CurrentOffset
;
1182 ULONG BytesRead
, BytesLeft
, CopyLength
;
1183 PVOID Source
, Destination
;
1187 // Get the MDL and check if it's mapped
1189 Mdl
= Irp
->MdlAddress
;
1190 if (Mdl
->MdlFlags
& (MDL_MAPPED_TO_SYSTEM_VA
| MDL_SOURCE_IS_NONPAGED_POOL
))
1193 // Use the mapped address
1195 SystemVa
= Mdl
->MappedSystemVa
;
1202 SystemVa
= MmMapLockedPagesSpecifyCache(Mdl
,
1207 NormalPagePriority
);
1211 // Make sure we were able to map it
1213 CurrentBase
= SystemVa
;
1214 if (!SystemVa
) return STATUS_INSUFFICIENT_RESOURCES
;
1217 // Initialize default
1219 Irp
->IoStatus
.Information
= 0;
1222 // Get the I/O Stack Location and capture the data
1224 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
1225 CurrentOffset
= IoStackLocation
->Parameters
.Read
.ByteOffset
;
1226 BytesLeft
= IoStackLocation
->Parameters
.Read
.Length
;
1227 if (!BytesLeft
) return STATUS_INVALID_PARAMETER
;
1237 BaseAddress
= RamdiskMapPages(DeviceExtension
,
1241 if (!BaseAddress
) return STATUS_INSUFFICIENT_RESOURCES
;
1244 // Update our lengths
1246 Irp
->IoStatus
.Information
+= BytesRead
;
1247 CopyLength
= BytesRead
;
1250 // Check if this was a read or write
1252 Status
= STATUS_SUCCESS
;
1253 if (IoStackLocation
->MajorFunction
== IRP_MJ_READ
)
1256 // Set our copy parameters
1258 Destination
= CurrentBase
;
1259 Source
= BaseAddress
;
1262 else if (IoStackLocation
->MajorFunction
== IRP_MJ_WRITE
)
1265 // Set our copy parameters
1267 Destination
= BaseAddress
;
1268 Source
= CurrentBase
;
1273 RtlCopyMemory(Destination
, Source
, CopyLength
);
1278 // Prepare us for failure
1280 BytesLeft
= CopyLength
;
1281 Status
= STATUS_INVALID_PARAMETER
;
1287 RamdiskUnmapPages(DeviceExtension
,
1293 // Update offset and bytes left
1295 BytesLeft
-= BytesRead
;
1296 CurrentOffset
.QuadPart
+= BytesRead
;
1297 CurrentBase
= (PVOID
)((ULONG_PTR
)CurrentBase
+ BytesRead
);
1300 // Check if we're done
1302 if (!BytesLeft
) return Status
;
1308 RamdiskOpenClose(IN PDEVICE_OBJECT DeviceObject
,
1314 Irp
->IoStatus
.Information
= 1;
1315 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1316 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1317 return STATUS_SUCCESS
;
1322 RamdiskReadWrite(IN PDEVICE_OBJECT DeviceObject
,
1325 PRAMDISK_DRIVE_EXTENSION DeviceExtension
;
1327 //LARGE_INTEGER ByteOffset;
1328 PIO_STACK_LOCATION IoStackLocation
;
1329 NTSTATUS Status
, ReturnStatus
;
1332 // Get the device extension and make sure this isn't a bus
1334 DeviceExtension
= DeviceObject
->DeviceExtension
;
1335 if (DeviceExtension
->Type
== RamdiskBus
)
1340 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1345 // Capture parameters
1347 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
1348 //Length = IoStackLocation->Parameters.Read.Length;
1349 //ByteOffset = IoStackLocation->Parameters.Read.ByteOffset;
1352 // FIXME: Validate offset
1356 // FIXME: Validate sector
1362 if ((IoStackLocation
->MajorFunction
== IRP_MJ_WRITE
) &&
1363 (DeviceExtension
->DiskOptions
.Readonly
))
1366 // Fail, this is read-only
1368 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
1373 // See if we want to do this sync or async
1375 if (DeviceExtension
->DiskType
> RAMDISK_MEMORY_MAPPED_DISK
)
1380 Status
= RamdiskReadWriteReal(Irp
, DeviceExtension
);
1385 // Queue it to the worker
1387 Status
= SendIrpToThread(DeviceObject
, Irp
);
1388 ReturnStatus
= STATUS_PENDING
;
1391 // Check if we're pending or not
1393 if (Status
!= STATUS_PENDING
)
1399 Irp
->IoStatus
.Status
= Status
;
1400 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1401 ReturnStatus
= Status
;
1407 return ReturnStatus
;
1412 RamdiskDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
1416 PIO_STACK_LOCATION IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
1417 PRAMDISK_BUS_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
1418 PRAMDISK_DRIVE_EXTENSION DriveExtension
= (PVOID
)DeviceExtension
;
1421 PDISK_GEOMETRY DiskGeometry
;
1424 // Grab the remove lock
1426 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, Irp
);
1427 if (!NT_SUCCESS(Status
))
1432 Irp
->IoStatus
.Information
= 0;
1433 Irp
->IoStatus
.Status
= Status
;
1434 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1439 // Setup some defaults
1441 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1445 // Check if this is an bus device or the drive
1447 if (DeviceExtension
->Type
== RamdiskBus
)
1450 // Check what the request is
1452 switch (IoStackLocation
->Parameters
.DeviceIoControl
.IoControlCode
)
1455 // Request to create a ramdisk
1457 case FSCTL_CREATE_RAM_DISK
:
1462 Status
= RamdiskCreateRamdisk(DeviceObject
, Irp
, TRUE
);
1463 if (!NT_SUCCESS(Status
)) goto CompleteRequest
;
1469 // We don't handle anything else yet
1471 UNIMPLEMENTED_DBGBREAK();
1477 // Check what the request is
1479 switch (IoStackLocation
->Parameters
.DeviceIoControl
.IoControlCode
)
1481 case IOCTL_DISK_CHECK_VERIFY
:
1482 case IOCTL_STORAGE_CHECK_VERIFY
:
1483 case IOCTL_STORAGE_CHECK_VERIFY2
:
1484 case IOCTL_CDROM_CHECK_VERIFY
:
1487 // Just pretend it's OK, don't do more
1489 Status
= STATUS_SUCCESS
;
1492 case IOCTL_STORAGE_GET_MEDIA_TYPES
:
1493 case IOCTL_DISK_GET_MEDIA_TYPES
:
1494 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
1495 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
:
1498 // Validate the length
1500 if (IoStackLocation
->Parameters
.DeviceIoControl
.
1501 OutputBufferLength
< sizeof(DISK_GEOMETRY
))
1506 Status
= STATUS_BUFFER_TOO_SMALL
;
1513 DiskGeometry
= Irp
->AssociatedIrp
.SystemBuffer
;
1514 DiskGeometry
->Cylinders
.QuadPart
= DriveExtension
->Cylinders
;
1515 DiskGeometry
->BytesPerSector
= DriveExtension
->BytesPerSector
;
1516 DiskGeometry
->SectorsPerTrack
= DriveExtension
->SectorsPerTrack
;
1517 DiskGeometry
->TracksPerCylinder
= DriveExtension
->NumberOfHeads
;
1518 DiskGeometry
->MediaType
= DriveExtension
->DiskOptions
.Fixed
?
1519 FixedMedia
: RemovableMedia
;
1524 Status
= STATUS_SUCCESS
;
1525 Information
= sizeof(DISK_GEOMETRY
);
1528 case IOCTL_CDROM_READ_TOC
:
1531 // Validate the length
1533 if (IoStackLocation
->Parameters
.DeviceIoControl
.
1534 OutputBufferLength
< sizeof(CDROM_TOC
))
1539 Status
= STATUS_BUFFER_TOO_SMALL
;
1546 Toc
= Irp
->AssociatedIrp
.SystemBuffer
;
1547 RtlZeroMemory(Toc
, sizeof(CDROM_TOC
));
1553 Toc
->Length
[1] = RAMDISK_TOC_SIZE
- sizeof(Toc
->Length
);
1554 Toc
->FirstTrack
= 1;
1556 Toc
->TrackData
[0].Adr
= 1;
1557 Toc
->TrackData
[0].Control
= TOC_DATA_TRACK
;
1558 Toc
->TrackData
[0].TrackNumber
= 1;
1563 Status
= STATUS_SUCCESS
;
1564 Information
= RAMDISK_TOC_SIZE
;
1567 case IOCTL_DISK_SET_PARTITION_INFO
:
1569 Status
= RamdiskSetPartitionInfo(Irp
, DriveExtension
);
1572 case IOCTL_DISK_GET_PARTITION_INFO
:
1575 // Validate the length
1577 if (IoStackLocation
->Parameters
.DeviceIoControl
.
1578 OutputBufferLength
< sizeof(PARTITION_INFORMATION
))
1583 Status
= STATUS_BUFFER_TOO_SMALL
;
1588 // Check if we need to do this sync or async
1590 if (DriveExtension
->DiskType
> RAMDISK_MEMORY_MAPPED_DISK
)
1593 // Call the helper function
1595 Status
= RamdiskGetPartitionInfo(Irp
, DriveExtension
);
1600 // Do it asynchronously later
1608 Information
= Irp
->IoStatus
.Information
;
1611 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
1613 UNIMPLEMENTED_DBGBREAK();
1616 case IOCTL_DISK_GET_LENGTH_INFO
:
1618 UNIMPLEMENTED_DBGBREAK();
1621 case IOCTL_DISK_IS_WRITABLE
:
1623 UNIMPLEMENTED_DBGBREAK();
1626 case IOCTL_SCSI_MINIPORT
:
1628 UNIMPLEMENTED_DBGBREAK();
1631 case IOCTL_STORAGE_QUERY_PROPERTY
:
1633 UNIMPLEMENTED_DBGBREAK();
1636 case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
:
1638 UNIMPLEMENTED_DBGBREAK();
1641 case IOCTL_MOUNTDEV_QUERY_STABLE_GUID
:
1643 UNIMPLEMENTED_DBGBREAK();
1646 case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
:
1648 UNIMPLEMENTED_DBGBREAK();
1651 case IOCTL_VOLUME_SET_GPT_ATTRIBUTES
:
1653 UNIMPLEMENTED_DBGBREAK();
1656 case IOCTL_VOLUME_GET_GPT_ATTRIBUTES
:
1658 UNIMPLEMENTED_DBGBREAK();
1661 case IOCTL_VOLUME_OFFLINE
:
1663 UNIMPLEMENTED_DBGBREAK();
1669 // Drive code not emulated
1671 DPRINT1("IOCTL: %lx\n", IoStackLocation
->Parameters
.DeviceIoControl
.IoControlCode
);
1676 // If requests drop down here, we just return them complete them
1678 goto CompleteRequest
;
1682 // Queue the request to our worker thread
1685 Status
= SendIrpToThread(DeviceObject
, Irp
);
1691 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, Irp
);
1692 if (Status
!= STATUS_PENDING
)
1695 // Complete the request
1697 Irp
->IoStatus
.Status
= Status
;
1698 Irp
->IoStatus
.Information
= Information
;
1699 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1710 RamdiskQueryDeviceRelations(IN DEVICE_RELATION_TYPE Type
,
1711 IN PDEVICE_OBJECT DeviceObject
,
1714 PRAMDISK_BUS_EXTENSION DeviceExtension
;
1715 PRAMDISK_DRIVE_EXTENSION DriveExtension
;
1716 PDEVICE_RELATIONS DeviceRelations
, OurDeviceRelations
;
1717 ULONG Count
, DiskCount
, FinalCount
;
1718 PLIST_ENTRY ListHead
, NextEntry
;
1719 PDEVICE_OBJECT
* DriveDeviceObject
;
1720 RAMDISK_DEVICE_STATE State
;
1723 // Get the device extension and check if this is a drive
1725 DeviceExtension
= DeviceObject
->DeviceExtension
;
1726 if (DeviceExtension
->Type
== RamdiskDrive
)
1731 UNIMPLEMENTED_DBGBREAK();
1735 // Anything but bus relations, we don't handle
1737 if (Type
) goto PassToNext
;
1740 // Acquire the disk list lock
1742 KeEnterCriticalRegion();
1743 ExAcquireFastMutex(&DeviceExtension
->DiskListLock
);
1746 // Did a device already fill relations?
1748 DeviceRelations
= (PDEVICE_RELATIONS
)Irp
->IoStatus
.Information
;
1749 if (DeviceRelations
)
1754 Count
= DeviceRelations
->Count
;
1765 // Now loop our drives
1768 ListHead
= &DeviceExtension
->DiskList
;
1769 NextEntry
= ListHead
->Flink
;
1770 while (NextEntry
!= ListHead
)
1773 // As long as it wasn't removed, count it in
1775 DriveExtension
= CONTAINING_RECORD(NextEntry
,
1776 RAMDISK_DRIVE_EXTENSION
,
1778 if (DriveExtension
->State
< RamdiskStateBusRemoved
) DiskCount
++;
1781 // Move to the next one
1783 NextEntry
= NextEntry
->Flink
;
1787 // Now we know our final count
1789 FinalCount
= Count
+ DiskCount
;
1792 // Allocate the structure
1794 OurDeviceRelations
= ExAllocatePoolWithTag(PagedPool
,
1795 FIELD_OFFSET(DEVICE_RELATIONS
,
1798 sizeof(PDEVICE_OBJECT
),
1800 if (!OurDeviceRelations
)
1805 ExReleaseFastMutex(&DeviceExtension
->DiskListLock
);
1806 KeLeaveCriticalRegion();
1807 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1808 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1809 return STATUS_INSUFFICIENT_RESOURCES
;
1813 // Check if we already had some relations
1820 RtlCopyMemory(OurDeviceRelations
->Objects
,
1821 DeviceRelations
->Objects
,
1822 Count
* sizeof(PDEVICE_OBJECT
));
1828 OurDeviceRelations
->Count
= FinalCount
;
1831 // Now loop our drives again
1833 ListHead
= &DeviceExtension
->DiskList
;
1834 NextEntry
= ListHead
->Flink
;
1835 while (NextEntry
!= ListHead
)
1838 // Go to the end of the list
1840 DriveDeviceObject
= &OurDeviceRelations
->Objects
[Count
];
1843 // Get the drive state
1845 DriveExtension
= CONTAINING_RECORD(NextEntry
,
1846 RAMDISK_DRIVE_EXTENSION
,
1848 State
= DriveExtension
->State
;
1851 // If it was removed or enumerated, we don't touch the device object
1853 if (State
>= RamdiskStateBusRemoved
)
1856 // If it was removed, we still have to keep track of this though
1858 if (State
== RamdiskStateBusRemoved
)
1861 // Mark it as enumerated now, but don't actually reference it
1863 DriveExtension
->State
= RamdiskStateEnumerated
;
1869 // First time it's enumerated, reference the device object
1871 ObReferenceObject(DriveExtension
->DeviceObject
);
1874 // Save the object pointer, and move on
1876 *DriveDeviceObject
++ = DriveExtension
->DeviceObject
;
1879 if (DriveExtension
->State
< RamdiskStateBusRemoved
) DiskCount
++;
1882 // Move to the next one
1884 NextEntry
= NextEntry
->Flink
;
1890 ExReleaseFastMutex(&DeviceExtension
->DiskListLock
);
1891 KeLeaveCriticalRegion();
1894 // Cleanup old relations
1896 if (DeviceRelations
) ExFreePool(DeviceRelations
);
1901 Irp
->IoStatus
.Information
= (ULONG_PTR
)OurDeviceRelations
;
1902 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1905 // Pass to the next driver
1908 IoCopyCurrentIrpStackLocationToNext(Irp
);
1909 return IoCallDriver(DeviceExtension
->AttachedDevice
, Irp
);
1914 RamdiskDeleteDiskDevice(IN PDEVICE_OBJECT DeviceObject
,
1917 UNIMPLEMENTED_DBGBREAK();
1918 return STATUS_SUCCESS
;
1923 RamdiskRemoveBusDevice(IN PDEVICE_OBJECT DeviceObject
,
1927 PLIST_ENTRY ListHead
, NextEntry
;
1928 PRAMDISK_BUS_EXTENSION DeviceExtension
;
1929 PRAMDISK_DRIVE_EXTENSION DriveExtension
;
1931 DeviceExtension
= DeviceObject
->DeviceExtension
;
1934 // Acquire disks list lock
1936 KeEnterCriticalRegion();
1937 ExAcquireFastMutex(&DeviceExtension
->DiskListLock
);
1942 ListHead
= &DeviceExtension
->DiskList
;
1943 NextEntry
= ListHead
->Flink
;
1944 while (NextEntry
!= ListHead
)
1946 DriveExtension
= CONTAINING_RECORD(NextEntry
,
1947 RAMDISK_DRIVE_EXTENSION
,
1953 IoAcquireRemoveLock(&DriveExtension
->RemoveLock
, NULL
);
1954 RamdiskDeleteDiskDevice(DriveExtension
->PhysicalDeviceObject
, NULL
);
1957 // RamdiskDeleteDiskDevice releases list lock, so reacquire it
1959 KeEnterCriticalRegion();
1960 ExAcquireFastMutex(&DeviceExtension
->DiskListLock
);
1964 // Release disks list lock
1966 ExReleaseFastMutex(&DeviceExtension
->DiskListLock
);
1967 KeLeaveCriticalRegion();
1970 // Prepare to pass to the lower driver
1972 IoSkipCurrentIrpStackLocation(Irp
);
1974 // Here everything went fine
1976 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1979 // Call lower driver
1981 Status
= IoCallDriver(DeviceExtension
->AttachedDevice
, Irp
);
1986 DeviceExtension
->State
= RamdiskStateBusRemoved
;
1989 // Release the lock, and ensure that everyone
1990 // has finished its job before we continue
1991 // The lock has been acquired by the dispatcher
1993 IoReleaseRemoveLockAndWait(&DeviceExtension
->RemoveLock
, Irp
);
1996 // If there's a drive name
1998 if (DeviceExtension
->DriveDeviceName
.Buffer
)
2001 // Inform it's going to be disabled
2002 // and free the drive name
2004 IoSetDeviceInterfaceState(&DeviceExtension
->DriveDeviceName
, FALSE
);
2005 RtlFreeUnicodeString(&DeviceExtension
->DriveDeviceName
);
2009 // Part from the stack, detach from lower device
2011 IoDetachDevice(DeviceExtension
->AttachedDevice
);
2014 // Finally, delete device
2016 RamdiskBusFdo
= NULL
;
2017 IoDeleteDevice(DeviceObject
);
2020 // Return status from lower driver
2027 RamdiskPnp(IN PDEVICE_OBJECT DeviceObject
,
2030 PIO_STACK_LOCATION IoStackLocation
;
2031 PRAMDISK_BUS_EXTENSION DeviceExtension
;
2036 // Get the device extension and stack location
2038 DeviceExtension
= DeviceObject
->DeviceExtension
;
2039 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
2040 Minor
= IoStackLocation
->MinorFunction
;
2043 // Check if the bus is removed
2045 if (DeviceExtension
->State
== RamdiskStateBusRemoved
)
2048 // Only remove-device and query-id are allowed
2050 if ((Minor
!= IRP_MN_REMOVE_DEVICE
) && (Minor
!= IRP_MN_QUERY_ID
))
2053 // Fail anything else
2055 Status
= STATUS_NO_SUCH_DEVICE
;
2056 Irp
->IoStatus
.Status
= Status
;
2057 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2063 // Acquire the remove lock
2065 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, Irp
);
2066 if (!NT_SUCCESS(Status
))
2071 Irp
->IoStatus
.Information
= 0;
2072 Irp
->IoStatus
.Status
= Status
;
2073 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2078 // Query the IRP type
2082 case IRP_MN_START_DEVICE
:
2084 UNIMPLEMENTED_DBGBREAK("PnP IRP: %lx\n", Minor
);
2087 case IRP_MN_QUERY_STOP_DEVICE
:
2089 UNIMPLEMENTED_DBGBREAK("PnP IRP: %lx\n", Minor
);
2092 case IRP_MN_CANCEL_STOP_DEVICE
:
2094 UNIMPLEMENTED_DBGBREAK("PnP IRP: %lx\n", Minor
);
2097 case IRP_MN_STOP_DEVICE
:
2099 UNIMPLEMENTED_DBGBREAK("PnP IRP: %lx\n", Minor
);
2102 case IRP_MN_QUERY_REMOVE_DEVICE
:
2104 UNIMPLEMENTED_DBGBREAK("PnP IRP: %lx\n", Minor
);
2107 case IRP_MN_CANCEL_REMOVE_DEVICE
:
2109 UNIMPLEMENTED_DBGBREAK("PnP IRP: %lx\n", Minor
);
2112 case IRP_MN_REMOVE_DEVICE
:
2115 // Remove the proper device
2117 if (DeviceExtension
->Type
== RamdiskBus
)
2119 Status
= RamdiskRemoveBusDevice(DeviceObject
, Irp
);
2122 // Return here, lower device has already been called
2123 // And remove lock released. This is needed by the function.
2129 Status
= RamdiskDeleteDiskDevice(DeviceObject
, Irp
);
2132 // Complete the IRP here and return
2133 // Here again we don't have to release remove lock
2134 // This has already been done by the function.
2136 Irp
->IoStatus
.Status
= Status
;
2137 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2141 case IRP_MN_SURPRISE_REMOVAL
:
2143 UNIMPLEMENTED_DBGBREAK("PnP IRP: %lx\n", Minor
);
2146 case IRP_MN_QUERY_ID
:
2151 if (DeviceExtension
->Type
== RamdiskDrive
)
2153 UNIMPLEMENTED_DBGBREAK("PnP IRP: %lx\n", Minor
);
2157 case IRP_MN_QUERY_BUS_INFORMATION
:
2162 if (DeviceExtension
->Type
== RamdiskDrive
)
2164 UNIMPLEMENTED_DBGBREAK("PnP IRP: %lx\n", Minor
);
2170 UNIMPLEMENTED_DBGBREAK("PnP IRP: %lx\n", Minor
);
2173 case IRP_MN_QUERY_DEVICE_TEXT
:
2178 if (DeviceExtension
->Type
== RamdiskDrive
)
2180 UNIMPLEMENTED_DBGBREAK("PnP IRP: %lx\n", Minor
);
2184 case IRP_MN_QUERY_DEVICE_RELATIONS
:
2187 // Call our main routine
2189 Status
= RamdiskQueryDeviceRelations(IoStackLocation
->
2191 QueryDeviceRelations
.Type
,
2194 goto ReleaseAndReturn
;
2196 case IRP_MN_QUERY_CAPABILITIES
:
2201 if (DeviceExtension
->Type
== RamdiskDrive
)
2203 UNIMPLEMENTED_DBGBREAK("PnP IRP: %lx\n", Minor
);
2207 case IRP_MN_QUERY_RESOURCES
:
2208 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS
:
2211 // Complete immediately without touching it
2213 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2214 goto ReleaseAndReturn
;
2218 DPRINT1("Illegal IRP: %lx\n", Minor
);
2225 if (DeviceExtension
->Type
== RamdiskBus
)
2228 // Do we have an attached device?
2230 if (DeviceExtension
->AttachedDevice
)
2235 IoSkipCurrentIrpStackLocation(Irp
);
2236 Status
= IoCallDriver(DeviceExtension
->AttachedDevice
, Irp
);
2241 // Release the lock and return status
2244 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, Irp
);
2250 RamdiskPower(IN PDEVICE_OBJECT DeviceObject
,
2254 PIO_STACK_LOCATION IoStackLocation
;
2255 PRAMDISK_BUS_EXTENSION DeviceExtension
;
2257 DeviceExtension
= DeviceObject
->DeviceExtension
;
2260 // If we have a device extension, take extra caution
2261 // with the lower driver
2263 if (DeviceExtension
!= NULL
)
2265 PoStartNextPowerIrp(Irp
);
2268 // Device has not been removed yet, so
2269 // pass to the attached/lower driver
2271 if (DeviceExtension
->State
< RamdiskStateBusRemoved
)
2273 IoSkipCurrentIrpStackLocation(Irp
);
2274 return PoCallDriver(DeviceExtension
->AttachedDevice
, Irp
);
2277 // Otherwise, simply complete the IRP
2278 // Notifying that deletion is pending
2282 Irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
2283 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2284 return STATUS_DELETE_PENDING
;
2289 // Get stack and deal with minor functions
2291 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
2292 switch (IoStackLocation
->MinorFunction
)
2294 case IRP_MN_SET_POWER
:
2296 // If setting device power state
2297 // it's all fine and return success
2299 if (DevicePowerState
)
2301 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2305 // Get appropriate status for return
2307 Status
= Irp
->IoStatus
.Status
;
2308 PoStartNextPowerIrp(Irp
);
2309 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2312 case IRP_MN_QUERY_POWER
:
2314 // We can obviously accept all states
2315 // So just return success
2318 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2319 PoStartNextPowerIrp(Irp
);
2320 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2325 // Just complete and save status for return
2327 Status
= Irp
->IoStatus
.Status
;
2328 PoStartNextPowerIrp(Irp
);
2329 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2338 RamdiskSystemControl(IN PDEVICE_OBJECT DeviceObject
,
2342 PRAMDISK_BUS_EXTENSION DeviceExtension
;
2344 DeviceExtension
= DeviceObject
->DeviceExtension
;
2347 // If we have a device extension, forward the IRP
2348 // to the attached device
2350 if (DeviceExtension
!= NULL
)
2352 IoSkipCurrentIrpStackLocation(Irp
);
2353 Status
= IoCallDriver(DeviceExtension
->AttachedDevice
, Irp
);
2356 // Otherwise just complete the request
2357 // And return the status with which we complete it
2361 Status
= Irp
->IoStatus
.Status
;
2362 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2370 RamdiskScsi(IN PDEVICE_OBJECT DeviceObject
,
2374 PRAMDISK_BUS_EXTENSION DeviceExtension
;
2376 DeviceExtension
= DeviceObject
->DeviceExtension
;
2379 // Having a proper device is mandatory
2381 if (DeviceExtension
->State
> RamdiskStateStopped
)
2383 Status
= STATUS_DEVICE_DOES_NOT_EXIST
;
2388 // Acquire the remove lock
2390 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, Irp
);
2391 if (!NT_SUCCESS(Status
))
2397 // Queue the IRP for worker
2399 Status
= SendIrpToThread(DeviceObject
, Irp
);
2400 if (Status
!= STATUS_PENDING
)
2406 // Release the remove lock
2408 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, Irp
);
2412 Irp
->IoStatus
.Information
= 0;
2413 Irp
->IoStatus
.Status
= Status
;
2414 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2422 RamdiskFlushBuffers(IN PDEVICE_OBJECT DeviceObject
,
2426 PRAMDISK_DRIVE_EXTENSION DeviceExtension
;
2428 DeviceExtension
= DeviceObject
->DeviceExtension
;
2431 // Ensure we have drive extension
2432 // Only perform flush on disks that have been created
2433 // from registry entries
2435 if (DeviceExtension
->Type
!= RamdiskDrive
||
2436 DeviceExtension
->DiskType
> RAMDISK_MEMORY_MAPPED_DISK
)
2438 Irp
->IoStatus
.Information
= 0;
2439 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2440 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2441 return STATUS_SUCCESS
;
2445 // Queue the IRP for worker
2447 Status
= SendIrpToThread(DeviceObject
, Irp
);
2448 if (Status
!= STATUS_PENDING
)
2451 // Queueing failed - complete the IRP
2452 // and return failure
2454 Irp
->IoStatus
.Information
= 0;
2455 Irp
->IoStatus
.Status
= Status
;
2456 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2464 RamdiskUnload(IN PDRIVER_OBJECT DriverObject
)
2467 // Just release registry path if previously allocated
2469 if (DriverRegistryPath
.Buffer
)
2471 ExFreePoolWithTag(DriverRegistryPath
.Buffer
, 'dmaR');
2477 RamdiskAddDevice(IN PDRIVER_OBJECT DriverObject
,
2478 IN PDEVICE_OBJECT PhysicalDeviceObject
)
2480 PRAMDISK_BUS_EXTENSION DeviceExtension
;
2481 PDEVICE_OBJECT AttachedDevice
;
2483 UNICODE_STRING DeviceName
;
2484 PDEVICE_OBJECT DeviceObject
;
2487 // Only create the bus FDO once
2489 if (RamdiskBusFdo
) return STATUS_DEVICE_ALREADY_ATTACHED
;
2492 // Create the bus FDO
2494 RtlInitUnicodeString(&DeviceName
, L
"\\Device\\Ramdisk");
2495 Status
= IoCreateDevice(DriverObject
,
2496 sizeof(RAMDISK_BUS_EXTENSION
),
2498 FILE_DEVICE_BUS_EXTENDER
,
2499 FILE_DEVICE_SECURE_OPEN
,
2502 if (NT_SUCCESS(Status
))
2505 // Initialize the bus FDO extension
2507 DeviceExtension
= DeviceObject
->DeviceExtension
;
2508 RtlZeroMemory(DeviceObject
->DeviceExtension
,
2509 sizeof(RAMDISK_BUS_EXTENSION
));
2512 // Set bus FDO flags
2514 DeviceObject
->Flags
|= DO_POWER_PAGABLE
| DO_DIRECT_IO
;
2517 // Setup the bus FDO extension
2519 DeviceExtension
->Type
= RamdiskBus
;
2520 ExInitializeFastMutex(&DeviceExtension
->DiskListLock
);
2521 IoInitializeRemoveLock(&DeviceExtension
->RemoveLock
,
2525 InitializeListHead(&DeviceExtension
->DiskList
);
2526 DeviceExtension
->PhysicalDeviceObject
= PhysicalDeviceObject
;
2527 DeviceExtension
->DeviceObject
= DeviceObject
;
2530 // Register the RAM disk device interface
2532 Status
= IoRegisterDeviceInterface(PhysicalDeviceObject
,
2533 &RamdiskBusInterface
,
2535 &DeviceExtension
->BusDeviceName
);
2536 if (!NT_SUCCESS(Status
))
2541 IoDeleteDevice(DeviceObject
);
2546 // Attach us to the device stack
2548 AttachedDevice
= IoAttachDeviceToDeviceStack(DeviceObject
,
2549 PhysicalDeviceObject
);
2550 DeviceExtension
->AttachedDevice
= AttachedDevice
;
2551 if (!AttachedDevice
)
2556 IoSetDeviceInterfaceState(&DeviceExtension
->BusDeviceName
, 0);
2557 RtlFreeUnicodeString(&DeviceExtension
->BusDeviceName
);
2558 IoDeleteDevice(DeviceObject
);
2559 return STATUS_NO_SUCH_DEVICE
;
2563 // Bus FDO is initialized
2565 RamdiskBusFdo
= DeviceObject
;
2568 // Loop for loader block
2573 // Are we being booted from setup? Not yet supported
2575 //ASSERT(!KeLoaderBlock->SetupLdrBlock);
2581 DeviceObject
->Flags
&= DO_DEVICE_INITIALIZING
;
2582 Status
= STATUS_SUCCESS
;
2593 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
2594 IN PUNICODE_STRING RegistryPath
)
2596 PCHAR BootDeviceName
, CommandLine
;
2597 PDEVICE_OBJECT PhysicalDeviceObject
= NULL
;
2599 DPRINT("RAM Disk Driver Initialized\n");
2602 // Query ramdisk parameters
2604 QueryParameters(RegistryPath
);
2607 // Save the registry path
2609 DriverRegistryPath
= *RegistryPath
;
2610 DriverRegistryPath
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
2611 RegistryPath
->Length
+
2614 if (!DriverRegistryPath
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
2615 RtlCopyUnicodeString(&DriverRegistryPath
, RegistryPath
);
2618 // Set device routines
2620 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = RamdiskOpenClose
;
2621 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = RamdiskOpenClose
;
2622 DriverObject
->MajorFunction
[IRP_MJ_READ
] = RamdiskReadWrite
;
2623 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = RamdiskReadWrite
;
2624 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = RamdiskDeviceControl
;
2625 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = RamdiskPnp
;
2626 DriverObject
->MajorFunction
[IRP_MJ_POWER
] = RamdiskPower
;
2627 DriverObject
->MajorFunction
[IRP_MJ_SYSTEM_CONTROL
] = RamdiskSystemControl
;
2628 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = RamdiskScsi
;
2629 DriverObject
->MajorFunction
[IRP_MJ_FLUSH_BUFFERS
] = RamdiskFlushBuffers
;
2630 DriverObject
->DriverExtension
->AddDevice
= RamdiskAddDevice
;
2631 DriverObject
->DriverUnload
= RamdiskUnload
;
2634 // Check for a loader block
2639 // Get the boot device name
2641 BootDeviceName
= KeLoaderBlock
->ArcBootDeviceName
;
2645 // Check if we're booting from ramdisk
2647 if ((strlen(BootDeviceName
) >= 10) &&
2648 !(_strnicmp(BootDeviceName
, "ramdisk(0)", 10)))
2651 // We'll have to tell the PnP Manager
2653 ReportDetectedDevice
= TRUE
;
2656 // Check for a command line
2658 CommandLine
= KeLoaderBlock
->LoadOptions
;
2662 // Check if this is an ISO boot
2664 if (strstr(CommandLine
, "RDEXPORTASCD"))
2667 // Remember for later
2669 ExportBootDiskAsCd
= TRUE
;
2673 // Check if this is PE boot
2675 if (strstr(CommandLine
, "MININT"))
2678 // Remember for later
2689 // Installing from Ramdisk isn't supported yet
2691 //ASSERT(!KeLoaderBlock->SetupLdrBlock);
2694 // Are we reporting the device
2696 if (ReportDetectedDevice
)
2701 Status
= IoReportDetectedDevice(DriverObject
,
2702 InterfaceTypeUndefined
,
2708 &PhysicalDeviceObject
);
2709 if (NT_SUCCESS(Status
))
2712 // Create the device object
2714 Status
= RamdiskAddDevice(DriverObject
, PhysicalDeviceObject
);
2715 if (NT_SUCCESS(Status
))
2720 PhysicalDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
2721 Status
= STATUS_SUCCESS
;
2730 Status
= STATUS_SUCCESS
;