1 /*
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
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include <initguid.h>
12 #include <ntddk.h>
13 #include <ntifs.h>
14 #include <ntdddisk.h>
15 #include <ntddcdrm.h>
16 #include <scsi.h>
17 #include <ntddscsi.h>
18 #include <ntddvol.h>
19 #include <mountdev.h>
20 #include <mountmgr.h>
21 #include <ketypes.h>
22 #include <iotypes.h>
23 #include <rtlfuncs.h>
24 #include <arc/arc.h>
25 #include <reactos/drivers/ntddrdsk.h>
26 #include "../../../filesystems/fs_rec/fs_rec.h"
27 #include <stdio.h>
28 #define NDEBUG
29 #include <debug.h>
30 
31 #define DO_XIP   0x00020000
32 
33 /* GLOBALS ********************************************************************/
34 
35 #define RAMDISK_SESSION_SIZE \
36     FIELD_OFFSET(CDROM_TOC, TrackData) + sizeof(TRACK_DATA)
37 
38 #define RAMDISK_TOC_SIZE \
39     FIELD_OFFSET(CDROM_TOC, TrackData) + 2 * sizeof(TRACK_DATA)
40 
41 #define TOC_DATA_TRACK              (0x04)
42 
43 typedef enum _RAMDISK_DEVICE_TYPE
44 {
45     RamdiskBus,
46     RamdiskDrive
47 } RAMDISK_DEVICE_TYPE;
48 
49 typedef enum _RAMDISK_DEVICE_STATE
50 {
51     RamdiskStateUninitialized,
52     RamdiskStateStarted,
53     RamdiskStatePaused,
54     RamdiskStateStopped,
55     RamdiskStateRemoved,
56     RamdiskStateBusRemoved,
57     RamdiskStateEnumerated,
58 } RAMDISK_DEVICE_STATE;
59 
60 DEFINE_GUID(RamdiskBusInterface,
61             0x5DC52DF0,
62             0x2F8A,
63             0x410F,
64             0x80, 0xE4, 0x05, 0xF8, 0x10, 0xE7, 0xA8, 0x8A);
65 
66 DEFINE_GUID(RamdiskDiskInterface,
67             0x31D909F0,
68             0x2CDF,
69             0x4A20,
70             0x9E, 0xD4, 0x7D, 0x65, 0x47, 0x6C, 0xA7, 0x68);
71 
72 typedef struct _RAMDISK_EXTENSION
73 {
74     RAMDISK_DEVICE_TYPE Type;
75     RAMDISK_DEVICE_STATE State;
76     PDEVICE_OBJECT DeviceObject;
77     PDEVICE_OBJECT PhysicalDeviceObject;
78     PDEVICE_OBJECT AttachedDevice;
79     IO_REMOVE_LOCK RemoveLock;
80     UNICODE_STRING DriveDeviceName;
81     UNICODE_STRING BusDeviceName;
82     FAST_MUTEX DiskListLock;
83     LIST_ENTRY DiskList;
84 } RAMDISK_EXTENSION, *PRAMDISK_EXTENSION;
85 
86 typedef struct _RAMDISK_BUS_EXTENSION
87 {
88     RAMDISK_EXTENSION;
89 } RAMDISK_BUS_EXTENSION, *PRAMDISK_BUS_EXTENSION;
90 
91 typedef struct _RAMDISK_DRIVE_EXTENSION
92 {
93     /* Inherited base class */
94     RAMDISK_EXTENSION;
95 
96     /* Data we get from the creator */
97     GUID DiskGuid;
98     UNICODE_STRING GuidString;
99     UNICODE_STRING SymbolicLinkName;
100     ULONG DiskType;
101     RAMDISK_CREATE_OPTIONS DiskOptions;
102     LARGE_INTEGER DiskLength;
103     LONG DiskOffset;
104     WCHAR DriveLetter;
105     ULONG BasePage;
106 
107     /* Data we get from the disk */
108     ULONG BytesPerSector;
109     ULONG SectorsPerTrack;
110     ULONG NumberOfHeads;
111     ULONG Cylinders;
112     ULONG HiddenSectors;
113 } RAMDISK_DRIVE_EXTENSION, *PRAMDISK_DRIVE_EXTENSION;
114 
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;
126 BOOLEAN IsWinPEBoot;
127 PDEVICE_OBJECT RamdiskBusFdo;
128 
129 /* FUNCTIONS ******************************************************************/
130 
131 VOID
132 NTAPI
133 QueryParameters(IN PUNICODE_STRING RegistryPath)
134 {
135     ULONG MinView, DefView, MinViewLength, DefViewLength, MaxViewLength;
136     RTL_QUERY_REGISTRY_TABLE QueryTable[11];
137 
138     /* Set defaults */
139     MaximumViewLength = 0x10000000u;
140     MaximumPerDiskViewLength = 0x10000000u;
141     ReportDetectedDevice = 0;
142     MarkRamdisksAsRemovable = 0;
143     MinimumViewCount = 2;
144     DefaultViewCount = 16;
145     MaximumViewCount = 64;
146     MinimumViewLength = 0x10000u;
147     DefaultViewLength = 0x100000u;
148 
149     /* Setup the query table and query the registry */
150     RtlZeroMemory(QueryTable, sizeof(QueryTable));
151     QueryTable[0].Flags = 1;
152     QueryTable[0].Name = L"Parameters";
153     QueryTable[1].Flags = 32;
154     QueryTable[1].Name = L"ReportDetectedDevice";
155     QueryTable[1].EntryContext = &ReportDetectedDevice;
156     QueryTable[2].Flags = 32;
157     QueryTable[2].Name = L"MarkRamdisksAsRemovable";
158     QueryTable[2].EntryContext = &MarkRamdisksAsRemovable;
159     QueryTable[3].Flags = 32;
160     QueryTable[3].Name = L"MinimumViewCount";
161     QueryTable[3].EntryContext = &MinimumViewCount;
162     QueryTable[4].Flags = 32;
163     QueryTable[4].Name = L"DefaultViewCount";
164     QueryTable[4].EntryContext = &DefaultViewCount;
165     QueryTable[5].Flags = 32;
166     QueryTable[5].Name = L"MaximumViewCount";
167     QueryTable[5].EntryContext = &MaximumViewCount;
168     QueryTable[6].Flags = 32;
169     QueryTable[6].Name = L"MinimumViewLength";
170     QueryTable[6].EntryContext = &MinimumViewLength;
171     QueryTable[7].Flags = 32;
172     QueryTable[7].Name = L"DefaultViewLength";
173     QueryTable[7].EntryContext = &DefaultViewLength;
174     QueryTable[8].Flags = 32;
175     QueryTable[8].Name = L"MaximumViewLength";
176     QueryTable[8].EntryContext = &MaximumViewLength;
177     QueryTable[9].Flags = 32;
178     QueryTable[9].Name = L"MaximumPerDiskViewLength";
179     QueryTable[9].EntryContext = &MaximumPerDiskViewLength;
180     RtlQueryRegistryValues(RTL_REGISTRY_OPTIONAL,
181                            RegistryPath->Buffer,
182                            QueryTable,
183                            NULL,
184                            NULL);
185 
186     /* Parse minimum view count, cannot be bigger than 256 or smaller than 2 */
187     MinView = MinimumViewCount;
188     if (MinimumViewCount >= 2)
189     {
190         if (MinimumViewCount > 256) MinView = 256;
191     }
192     else
193     {
194         MinView = 2;
195     }
196     MinimumViewCount = MinView;
197 
198     /* Parse default view count, cannot be bigger than 256 or smaller than minimum */
199     DefView = DefaultViewCount;
200     if (DefaultViewCount >= MinView)
201     {
202         if (DefaultViewCount > 256) DefView = 256;
203     }
204     else
205     {
206         DefView = MinView;
207     }
208     DefaultViewCount = DefView;
209 
210     /* Parse maximum view count, cannot be bigger than 256 or smaller than default */
211     if (MaximumViewCount >= DefView)
212     {
213         if (MaximumViewCount > 256) MaximumViewCount = 256;
214     }
215     else
216     {
217         MaximumViewCount = DefView;
218     }
219 
220     /* Parse minimum view length, cannot be bigger than 1GB or smaller than 64KB */
221     MinViewLength = MinimumViewLength;
222     if (MinimumViewLength >= 0x10000)
223     {
224         if (MinimumViewLength > 0x40000000) MinViewLength = 0x40000000u;
225     }
226     else
227     {
228         MinViewLength = 0x10000u;
229     }
230     MinimumViewLength = MinViewLength;
231 
232     /* Parse default view length, cannot be bigger than 1GB or smaller than minimum */
233     DefViewLength = DefaultViewLength;
234     if (DefaultViewLength >= MinViewLength)
235     {
236         if (DefaultViewLength > 0x40000000) DefViewLength = 0x40000000u;
237     }
238     else
239     {
240         DefViewLength = MinViewLength;
241     }
242     DefaultViewLength = DefViewLength;
243 
244     /* Parse maximum view length, cannot be bigger than 1GB or smaller than default */
245     MaxViewLength = MaximumViewLength;
246     if (MaximumViewLength >= DefViewLength)
247     {
248         if (MaximumViewLength > 0x40000000) MaxViewLength = 0x40000000u;
249     }
250     else
251     {
252         MaxViewLength = DefViewLength;
253     }
254     MaximumViewLength = MaxViewLength;
255 
256     /* Parse maximum view length per disk, cannot be smaller than 16MB */
257     if (MaximumPerDiskViewLength >= 0x1000000)
258     {
259         if (MaxViewLength > 0xFFFFFFFF) MaximumPerDiskViewLength = -1;
260     }
261     else
262     {
263         MaximumPerDiskViewLength = 0x1000000u;
264     }
265 }
266 
267 PVOID
268 NTAPI
269 RamdiskMapPages(IN PRAMDISK_DRIVE_EXTENSION DeviceExtension,
270                 IN LARGE_INTEGER Offset,
271                 IN ULONG Length,
272                 OUT PULONG OutputLength)
273 {
274     PHYSICAL_ADDRESS PhysicalAddress;
275     PVOID MappedBase;
276     ULONG PageOffset;
277     SIZE_T ActualLength;
278     LARGE_INTEGER ActualOffset;
279     LARGE_INTEGER ActualPages;
280 
281     /* We only support boot disks for now */
282     ASSERT(DeviceExtension->DiskType == RAMDISK_BOOT_DISK);
283 
284     /* Calculate the actual offset in the drive */
285     ActualOffset.QuadPart = DeviceExtension->DiskOffset + Offset.QuadPart;
286 
287     /* Convert to pages */
288     ActualPages.QuadPart = ActualOffset.QuadPart >> PAGE_SHIFT;
289 
290     /* Now add the base page */
291     ActualPages.QuadPart = DeviceExtension->BasePage + ActualPages.QuadPart;
292 
293     /* Calculate final amount of bytes */
294     PhysicalAddress.QuadPart = ActualPages.QuadPart << PAGE_SHIFT;
295 
296     /* Calculate pages spanned for the mapping */
297     ActualLength = ADDRESS_AND_SIZE_TO_SPAN_PAGES(ActualOffset.QuadPart, Length);
298 
299     /* And convert this back to bytes */
300     ActualLength <<= PAGE_SHIFT;
301 
302     /* Get the offset within the page */
303     PageOffset = BYTE_OFFSET(ActualOffset.QuadPart);
304 
305     /* Map the I/O Space from the loader */
306     MappedBase = MmMapIoSpace(PhysicalAddress, ActualLength, MmCached);
307 
308     /* Return actual offset within the page as well as the length */
309     if (MappedBase) MappedBase = (PVOID)((ULONG_PTR)MappedBase + PageOffset);
310     *OutputLength = Length;
311     return MappedBase;
312 }
313 
314 VOID
315 NTAPI
316 RamdiskUnmapPages(IN PRAMDISK_DRIVE_EXTENSION DeviceExtension,
317                   IN PVOID BaseAddress,
318                   IN LARGE_INTEGER Offset,
319                   IN ULONG Length)
320 {
321     LARGE_INTEGER ActualOffset;
322     SIZE_T ActualLength;
323     ULONG PageOffset;
324 
325     /* We only support boot disks for now */
326     ASSERT(DeviceExtension->DiskType == RAMDISK_BOOT_DISK);
327 
328     /* Calculate the actual offset in the drive */
329     ActualOffset.QuadPart = DeviceExtension->DiskOffset + Offset.QuadPart;
330 
331     /* Calculate pages spanned for the mapping */
332     ActualLength = ADDRESS_AND_SIZE_TO_SPAN_PAGES(ActualOffset.QuadPart, Length);
333 
334     /* And convert this back to bytes */
335     ActualLength <<= PAGE_SHIFT;
336 
337     /* Get the offset within the page */
338     PageOffset = BYTE_OFFSET(ActualOffset.QuadPart);
339 
340     /* Calculate actual base address where we mapped this */
341     BaseAddress = (PVOID)((ULONG_PTR)BaseAddress - PageOffset);
342 
343     /* Unmap the I/O space we got from the loader */
344     MmUnmapIoSpace(BaseAddress, ActualLength);
345 }
346 
347 NTSTATUS
348 NTAPI
349 RamdiskCreateDiskDevice(IN PRAMDISK_BUS_EXTENSION DeviceExtension,
350                         IN PRAMDISK_CREATE_INPUT Input,
351                         IN BOOLEAN ValidateOnly,
352                         OUT PRAMDISK_DRIVE_EXTENSION *NewDriveExtension)
353 {
354     ULONG BasePage, DiskType, Length;
355     //ULONG ViewCount;
356     NTSTATUS Status;
357     PDEVICE_OBJECT DeviceObject;
358     PRAMDISK_DRIVE_EXTENSION DriveExtension;
359     PVOID Buffer;
360     WCHAR LocalBuffer[16];
361     UNICODE_STRING SymbolicLinkName, DriveString, GuidString, DeviceName;
362     PPACKED_BOOT_SECTOR BootSector;
363     BIOS_PARAMETER_BLOCK BiosBlock;
364     ULONG BytesPerSector, SectorsPerTrack, Heads, BytesRead;
365     PVOID BaseAddress;
366     LARGE_INTEGER CurrentOffset, CylinderSize, DiskLength;
367     ULONG CylinderCount, SizeByCylinders;
368 
369     /* Check if we're a boot RAM disk */
370     DiskType = Input->DiskType;
371     if (DiskType >= RAMDISK_BOOT_DISK)
372     {
373         /* Check if we're an ISO */
374         if (DiskType == RAMDISK_BOOT_DISK)
375         {
376             /* NTLDR mounted us somewhere */
377             BasePage = Input->BasePage;
378             if (!BasePage) return STATUS_INVALID_PARAMETER;
379 
380             /* Sanitize disk options */
381             Input->Options.Fixed = TRUE;
382             Input->Options.Readonly = Input->Options.ExportAsCd |
383                                       Input->Options.Readonly;
384             Input->Options.Hidden = FALSE;
385             Input->Options.NoDosDevice = FALSE;
386             Input->Options.NoDriveLetter = IsWinPEBoot ? TRUE : FALSE;
387         }
388         else
389         {
390             /* The only other possibility is a WIM disk */
391             if (DiskType != RAMDISK_WIM_DISK)
392             {
393                 /* Fail */
394                 return STATUS_INVALID_PARAMETER;
395             }
396 
397             /* Read the view count instead */
398             // ViewCount = Input->ViewCount;
399 
400             /* Sanitize disk options */
401             Input->Options.Hidden = FALSE;
402             Input->Options.NoDosDevice = FALSE;
403             Input->Options.Readonly = FALSE;
404             Input->Options.NoDriveLetter = TRUE;
405             Input->Options.Fixed = TRUE;
406         }
407 
408         /* Are we just validating and returning to the user? */
409         if (ValidateOnly) return STATUS_SUCCESS;
410 
411         /* Build the GUID string */
412         Status = RtlStringFromGUID(&Input->DiskGuid, &GuidString);
413         if (!(NT_SUCCESS(Status)) || !(GuidString.Buffer))
414         {
415             /* Fail */
416             Status = STATUS_INSUFFICIENT_RESOURCES;
417             goto FailCreate;
418         }
419 
420         /* Allocate our device name */
421         Length = GuidString.Length + 32;
422         Buffer = ExAllocatePoolWithTag(NonPagedPool, Length, 'dmaR');
423         if (!Buffer)
424         {
425             /* Fail */
426             Status = STATUS_INSUFFICIENT_RESOURCES;
427             goto FailCreate;
428         }
429 
430         /* Build the device name string */
431         DeviceName.Buffer = Buffer;
432         DeviceName.Length = Length - 2;
433         DeviceName.MaximumLength = Length;
434         wcsncpy(Buffer, L"\\Device\\Ramdisk", Length / sizeof(WCHAR));
435         wcsncat(Buffer, GuidString.Buffer, Length / sizeof(WCHAR));
436 
437         /* Create the drive device */
438         Status = IoCreateDevice(DeviceExtension->DeviceObject->DriverObject,
439                                 sizeof(RAMDISK_DRIVE_EXTENSION),
440                                 &DeviceName,
441                                 (Input->Options.ExportAsCd) ?
442                                 FILE_DEVICE_CD_ROM : FILE_DEVICE_DISK,
443                                 0,
444                                 0,
445                                 &DeviceObject);
446         if (!NT_SUCCESS(Status)) goto FailCreate;
447 
448         /* Grab the drive extension */
449         DriveExtension = DeviceObject->DeviceExtension;
450 
451         /* Check if we need a DOS device */
452         if (!Input->Options.NoDosDevice)
453         {
454             /* Build the symbolic link name */
455             SymbolicLinkName.MaximumLength = GuidString.Length + 36;
456             SymbolicLinkName.Length = GuidString.Length + 34;
457             Buffer = ExAllocatePoolWithTag(NonPagedPool,
458                                            SymbolicLinkName.MaximumLength,
459                                            'dmaR');
460             SymbolicLinkName.Buffer = Buffer;
461             if (Buffer)
462             {
463                 /* Create it */
464                 wcsncpy(Buffer,
465                         L"\\GLOBAL??\\Ramdisk",
466                         SymbolicLinkName.MaximumLength / sizeof(WCHAR));
467                 wcsncat(Buffer,
468                         GuidString.Buffer,
469                         SymbolicLinkName.MaximumLength / sizeof(WCHAR));
470                 Status = IoCreateSymbolicLink(&SymbolicLinkName, &DeviceName);
471                 if (!NT_SUCCESS(Status))
472                 {
473                     /* Nevermind... */
474                     Input->Options.NoDosDevice = TRUE;
475                     ExFreePool(Buffer);
476                     SymbolicLinkName.Buffer = NULL;
477                 }
478             }
479             else
480             {
481                 /* No DOS device */
482                 Input->Options.NoDosDevice = TRUE;
483             }
484 
485             /* Is this an ISO boot ramdisk? */
486             if (Input->DiskType == RAMDISK_BOOT_DISK)
487             {
488                 /* Does it need a drive letter? */
489                 if (!Input->Options.NoDriveLetter)
490                 {
491                     /* Build it and take over the existing symbolic link */
492                     _snwprintf(LocalBuffer,
493                                30,
494                                L"\\DosDevices\\%wc:",
495                                Input->DriveLetter);
496                     RtlInitUnicodeString(&DriveString, LocalBuffer);
497                     IoDeleteSymbolicLink(&DriveString);
498                     IoCreateSymbolicLink(&DriveString, &DeviceName);
499 
500                     /* Save the drive letter */
501                     DriveExtension->DriveLetter = Input->DriveLetter;
502                 }
503             }
504 
505         }
506 
507         /* Setup the device object flags */
508         DeviceObject->Flags |= (DO_XIP | DO_POWER_PAGABLE | DO_DIRECT_IO);
509         DeviceObject->AlignmentRequirement = 1;
510 
511         /* Build the drive FDO */
512         *NewDriveExtension = DriveExtension;
513         DriveExtension->Type = RamdiskDrive;
514         DiskLength = Input->DiskLength;
515         ExInitializeFastMutex(&DriveExtension->DiskListLock);
516         IoInitializeRemoveLock(&DriveExtension->RemoveLock, 'dmaR', 1, 0);
517         DriveExtension->DriveDeviceName = DeviceName;
518         DriveExtension->SymbolicLinkName = SymbolicLinkName;
519         DriveExtension->GuidString = GuidString;
520         DriveExtension->DiskGuid = Input->DiskGuid;
521         DriveExtension->PhysicalDeviceObject = DeviceObject;
522         DriveExtension->DeviceObject = RamdiskBusFdo;
523         DriveExtension->AttachedDevice = RamdiskBusFdo;
524         DriveExtension->DiskType = Input->DiskType;
525         DriveExtension->DiskOptions = Input->Options;
526         DriveExtension->DiskLength = DiskLength;
527         DriveExtension->DiskOffset = Input->DiskOffset;
528         DriveExtension->BasePage = Input->BasePage;
529         DriveExtension->BytesPerSector = 0;
530         DriveExtension->SectorsPerTrack = 0;
531         DriveExtension->NumberOfHeads = 0;
532 
533         /* Make sure we don't free it later */
534         DeviceName.Buffer = NULL;
535         SymbolicLinkName.Buffer = NULL;
536         GuidString.Buffer = NULL;
537 
538         /* Check if this is a boot disk, or a registry ram drive */
539         if (!(Input->Options.ExportAsCd) &&
540             (Input->DiskType == RAMDISK_BOOT_DISK))
541         {
542             /* Not an ISO boot, but it's a boot FS -- map it to figure out the
543              * drive settings */
544             CurrentOffset.QuadPart = 0;
545             BaseAddress = RamdiskMapPages(DriveExtension,
546                                           CurrentOffset,
547                                           PAGE_SIZE,
548                                           &BytesRead);
549             if (BaseAddress)
550             {
551                 /* Get the data */
552                 BootSector = (PPACKED_BOOT_SECTOR)BaseAddress;
553                 FatUnpackBios(&BiosBlock, &BootSector->PackedBpb);
554                 BytesPerSector = BiosBlock.BytesPerSector;
555                 SectorsPerTrack = BiosBlock.SectorsPerTrack;
556                 Heads = BiosBlock.Heads;
557 
558                 /* Save it */
559                 DriveExtension->BytesPerSector = BytesPerSector;
560                 DriveExtension->SectorsPerTrack = SectorsPerTrack;
561                 DriveExtension->NumberOfHeads = Heads;
562 
563                 /* Unmap now */
564                 CurrentOffset.QuadPart = 0;
565                 RamdiskUnmapPages(DriveExtension,
566                                   BaseAddress,
567                                   CurrentOffset,
568                                   BytesRead);
569             }
570             else
571             {
572                 /* Fail */
573                 Status = STATUS_INSUFFICIENT_RESOURCES;
574                 goto FailCreate;
575             }
576         }
577 
578         /* Check if the drive settings haven't been set yet */
579         if ((DriveExtension->BytesPerSector == 0) ||
580             (DriveExtension->SectorsPerTrack == 0) ||
581             (DriveExtension->NumberOfHeads == 0))
582         {
583             /* Check if this is a CD */
584             if (Input->Options.ExportAsCd)
585             {
586                 /* Setup partition parameters default for ISO 9660 */
587                 DriveExtension->BytesPerSector = 2048;
588                 DriveExtension->SectorsPerTrack = 32;
589                 DriveExtension->NumberOfHeads = 64;
590             }
591             else
592             {
593                 /* Setup partition parameters default for FAT */
594                 DriveExtension->BytesPerSector = 512;
595                 DriveExtension->SectorsPerTrack = 128;
596                 DriveExtension->NumberOfHeads = 16;
597             }
598         }
599 
600         /* Calculate the cylinder size */
601         CylinderSize.QuadPart = DriveExtension->BytesPerSector *
602                                 DriveExtension->SectorsPerTrack *
603                                 DriveExtension->NumberOfHeads;
604         CylinderCount = DiskLength.QuadPart / CylinderSize.QuadPart;
605         SizeByCylinders = CylinderSize.QuadPart * CylinderCount;
606         DriveExtension->Cylinders = CylinderCount;
607         if ((DiskLength.HighPart > 0) || (SizeByCylinders < DiskLength.LowPart))
608         {
609             /* Align cylinder size up */
610             DriveExtension->Cylinders++;
611         }
612 
613         /* Acquire the disk lock */
614         KeEnterCriticalRegion();
615         ExAcquireFastMutex(&DeviceExtension->DiskListLock);
616 
617         /* Insert us */
618         InsertTailList(&DeviceExtension->DiskList, &DriveExtension->DiskList);
619 
620         /* Release the lock */
621         ExReleaseFastMutex(&DeviceExtension->DiskListLock);
622         KeLeaveCriticalRegion();
623 
624         /* Clear init flag */
625         DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
626         return STATUS_SUCCESS;
627     }
628 
629 FailCreate:
630     UNIMPLEMENTED_DBGBREAK();
631     return STATUS_SUCCESS;
632 }
633 
634 NTSTATUS
635 NTAPI
636 RamdiskCreateRamdisk(IN PDEVICE_OBJECT DeviceObject,
637                      IN PIRP Irp,
638                      IN BOOLEAN ValidateOnly)
639 {
640     PRAMDISK_CREATE_INPUT Input;
641     ULONG Length;
642     PRAMDISK_BUS_EXTENSION DeviceExtension;
643     PRAMDISK_DRIVE_EXTENSION DriveExtension;
644     ULONG DiskType;
645     PWCHAR FileNameStart, FileNameEnd;
646     NTSTATUS Status;
647     PIO_STACK_LOCATION IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
648 
649     /* Get the device extension and our input data */
650     DeviceExtension = DeviceObject->DeviceExtension;
651     Length = IoStackLocation->Parameters.DeviceIoControl.InputBufferLength;
652     Input = (PRAMDISK_CREATE_INPUT)Irp->AssociatedIrp.SystemBuffer;
653 
654     /* Validate input parameters */
655     if ((Length < sizeof(RAMDISK_CREATE_INPUT)) ||
656         (Input->Version != sizeof(RAMDISK_CREATE_INPUT)))
657     {
658         return STATUS_INVALID_PARAMETER;
659     }
660 
661     /* Validate the disk type */
662     DiskType = Input->DiskType;
663     if (DiskType == RAMDISK_WIM_DISK) return STATUS_INVALID_PARAMETER;
664 
665     /* Look at the disk type */
666     if (DiskType == RAMDISK_BOOT_DISK)
667     {
668         /* We only allow this as an early-init boot */
669         if (!KeLoaderBlock) return STATUS_INVALID_PARAMETER;
670 
671         /* Save command-line flags */
672         if (ExportBootDiskAsCd) Input->Options.ExportAsCd = TRUE;
673         if (IsWinPEBoot) Input->Options.NoDriveLetter = TRUE;
674     }
675 
676     /* Validate the disk type */
677     if ((Input->Options.ExportAsCd) && (DiskType != RAMDISK_BOOT_DISK))
678     {
679         /* If the type isn't CDFS, it has to at least be raw CD */
680         if (DiskType != RAMDISK_MEMORY_MAPPED_DISK) return STATUS_INVALID_PARAMETER;
681     }
682 
683     /* Check if this is an actual file */
684     if (DiskType <= RAMDISK_MEMORY_MAPPED_DISK)
685     {
686         /* Validate the file name */
687         FileNameStart = (PWCHAR)((ULONG_PTR)Input + Length);
688         FileNameEnd = Input->FileName + 1;
689         while ((FileNameEnd < FileNameStart) && *(FileNameEnd)) FileNameEnd++;
690         if (FileNameEnd == FileNameStart) return STATUS_INVALID_PARAMETER;
691     }
692 
693     /* Create the actual device */
694     Status = RamdiskCreateDiskDevice(DeviceExtension,
695                                      Input,
696                                      ValidateOnly,
697                                      &DriveExtension);
698     if (NT_SUCCESS(Status))
699     {
700         /* Invalidate and set success */
701         IoInvalidateDeviceRelations(DeviceExtension->PhysicalDeviceObject, 0);
702         Irp->IoStatus.Information = STATUS_SUCCESS;
703     }
704 
705     /* We are done */
706     return Status;
707 }
708 
709 NTSTATUS
710 NTAPI
711 RamdiskGetPartitionInfo(IN PIRP Irp,
712                         IN PRAMDISK_DRIVE_EXTENSION DeviceExtension)
713 {
714     NTSTATUS Status;
715     PPARTITION_INFORMATION PartitionInfo;
716     PVOID BaseAddress;
717     LARGE_INTEGER Zero = {{0, 0}};
718     ULONG Length;
719     PIO_STACK_LOCATION IoStackLocation;
720 
721     /* Validate the length */
722     IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
723     if (IoStackLocation->Parameters.DeviceIoControl.
724         OutputBufferLength < sizeof(PARTITION_INFORMATION))
725     {
726         /* Invalid length */
727         Status = STATUS_BUFFER_TOO_SMALL;
728         Irp->IoStatus.Status = Status;
729         Irp->IoStatus.Information = 0;
730         return Status;
731     }
732 
733     /* Map the partition table */
734     BaseAddress = RamdiskMapPages(DeviceExtension, Zero, PAGE_SIZE, &Length);
735     if (!BaseAddress)
736     {
737         /* No memory */
738         Status = STATUS_INSUFFICIENT_RESOURCES;
739         Irp->IoStatus.Status = Status;
740         Irp->IoStatus.Information = 0;
741         return Status;
742     }
743 
744     /* Fill out the information */
745     PartitionInfo = Irp->AssociatedIrp.SystemBuffer;
746     PartitionInfo->StartingOffset.QuadPart = DeviceExtension->BytesPerSector;
747     PartitionInfo->PartitionLength.QuadPart = DeviceExtension->BytesPerSector *
748                                               DeviceExtension->SectorsPerTrack *
749                                               DeviceExtension->NumberOfHeads *
750                                               DeviceExtension->Cylinders;
751     PartitionInfo->HiddenSectors = DeviceExtension->HiddenSectors;
752     PartitionInfo->PartitionNumber = 0;
753     PartitionInfo->PartitionType = *((PCHAR)BaseAddress + 450);
754     PartitionInfo->BootIndicator = (DeviceExtension->DiskType ==
755                                     RAMDISK_BOOT_DISK) ? TRUE: FALSE;
756     PartitionInfo->RecognizedPartition = IsRecognizedPartition(PartitionInfo->
757                                                                PartitionType);
758     PartitionInfo->RewritePartition = FALSE;
759 
760     /* Unmap the partition table */
761     RamdiskUnmapPages(DeviceExtension, BaseAddress, Zero, Length);
762 
763     /* Done */
764     Irp->IoStatus.Status = STATUS_SUCCESS;
765     Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
766     return STATUS_SUCCESS;
767 }
768 
769 NTSTATUS
770 NTAPI
771 RamdiskSetPartitionInfo(IN PIRP Irp,
772                         IN PRAMDISK_DRIVE_EXTENSION DeviceExtension)
773 {
774     ULONG BytesRead;
775     NTSTATUS Status;
776     PVOID BaseAddress;
777     PIO_STACK_LOCATION Stack;
778     LARGE_INTEGER Zero = {{0, 0}};
779     PPARTITION_INFORMATION PartitionInfo;
780 
781     /* First validate input */
782     Stack = IoGetCurrentIrpStackLocation(Irp);
783     if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(PARTITION_INFORMATION))
784     {
785         Status = STATUS_INVALID_PARAMETER;
786         goto SetAndQuit;
787     }
788 
789     /* Map to get MBR */
790     BaseAddress = RamdiskMapPages(DeviceExtension, Zero, PAGE_SIZE, &BytesRead);
791     if (BaseAddress == NULL)
792     {
793         Status = STATUS_INSUFFICIENT_RESOURCES;
794         goto SetAndQuit;
795     }
796 
797     /* Set the new partition type on partition 0, field system indicator */
798     PartitionInfo = (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
799     *((PCHAR)BaseAddress + 450) = PartitionInfo->PartitionType;
800 
801     /* And unmap */
802     RamdiskUnmapPages(DeviceExtension, BaseAddress, Zero, BytesRead);
803     Status = STATUS_SUCCESS;
804 
805 SetAndQuit:
806     Irp->IoStatus.Status = Status;
807     Irp->IoStatus.Information = 0;
808     return Status;
809 }
810 
811 VOID
812 NTAPI
813 RamdiskWorkerThread(IN PDEVICE_OBJECT DeviceObject,
814                     IN PVOID Context)
815 {
816     PRAMDISK_BUS_EXTENSION DeviceExtension;
817     NTSTATUS Status;
818     PIO_STACK_LOCATION IoStackLocation;
819     PIRP Irp = Context;
820 
821     /* Get the stack location */
822     IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
823 
824     /* Free the work item */
825     IoFreeWorkItem(Irp->Tail.Overlay.DriverContext[0]);
826 
827     /* Grab the device extension and lock it */
828     DeviceExtension = DeviceObject->DeviceExtension;
829     Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Irp);
830     if (NT_SUCCESS(Status))
831     {
832         /* Discriminate by major code */
833         switch (IoStackLocation->MajorFunction)
834         {
835             /* Device control */
836             case IRP_MJ_DEVICE_CONTROL:
837             {
838                 /* Let's take a look at the IOCTL */
839                 switch (IoStackLocation->Parameters.DeviceIoControl.IoControlCode)
840                 {
841                     /* Ramdisk create request */
842                     case FSCTL_CREATE_RAM_DISK:
843                     {
844                         /* This time we'll do it for real */
845                         Status = RamdiskCreateRamdisk(DeviceObject, Irp, FALSE);
846                         break;
847                     }
848 
849                     case IOCTL_DISK_SET_PARTITION_INFO:
850                     {
851                         Status = RamdiskSetPartitionInfo(Irp, (PRAMDISK_DRIVE_EXTENSION)DeviceExtension);
852                         break;
853                     }
854 
855                     case IOCTL_DISK_GET_DRIVE_LAYOUT:
856                         UNIMPLEMENTED_DBGBREAK("Get drive layout request\n");
857                         break;
858 
859                     case IOCTL_DISK_GET_PARTITION_INFO:
860                     {
861                         Status = RamdiskGetPartitionInfo(Irp, (PRAMDISK_DRIVE_EXTENSION)DeviceExtension);
862                         break;
863                     }
864 
865                     default:
866                         UNIMPLEMENTED_DBGBREAK("Invalid request\n");
867                         break;
868                 }
869 
870                 /* We're here */
871                 break;
872             }
873 
874             /* Read or write request */
875             case IRP_MJ_READ:
876             case IRP_MJ_WRITE:
877                 UNIMPLEMENTED_DBGBREAK("Read/Write request\n");
878                 break;
879 
880             /* Internal request (SCSI?) */
881             case IRP_MJ_INTERNAL_DEVICE_CONTROL:
882                 UNIMPLEMENTED_DBGBREAK("SCSI request\n");
883                 break;
884 
885             /* Flush request */
886             case IRP_MJ_FLUSH_BUFFERS:
887                 UNIMPLEMENTED_DBGBREAK("Flush request\n");
888                 break;
889 
890             /* Anything else */
891             default:
892                 UNIMPLEMENTED_DBGBREAK("Invalid request: %lx\n",
893                                        IoStackLocation->MajorFunction);
894                 break;
895         }
896 
897         /* Complete the I/O */
898         IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp);
899         Irp->IoStatus.Status = Status;
900         Irp->IoStatus.Information = 0;
901         IoCompleteRequest(Irp, IO_DISK_INCREMENT);
902         return;
903     }
904 
905     /* Fail the I/O */
906     Irp->IoStatus.Status = Status;
907     Irp->IoStatus.Information = 0;
908     IoCompleteRequest(Irp, IO_NO_INCREMENT);
909 }
910 
911 NTSTATUS
912 NTAPI
913 SendIrpToThread(IN PDEVICE_OBJECT DeviceObject,
914                 IN PIRP Irp)
915 {
916     PIO_WORKITEM WorkItem;
917 
918     /* Mark the IRP pending */
919     IoMarkIrpPending(Irp);
920 
921     /* Allocate a work item */
922     WorkItem = IoAllocateWorkItem(DeviceObject);
923     if (WorkItem)
924     {
925         /* Queue it up */
926         Irp->Tail.Overlay.DriverContext[0] = WorkItem;
927         IoQueueWorkItem(WorkItem, RamdiskWorkerThread, DelayedWorkQueue, Irp);
928         return STATUS_PENDING;
929     }
930     else
931     {
932         /* Fail */
933         return STATUS_INSUFFICIENT_RESOURCES;
934     }
935 }
936 
937 NTSTATUS
938 NTAPI
939 RamdiskReadWriteReal(IN PIRP Irp,
940                      IN PRAMDISK_DRIVE_EXTENSION DeviceExtension)
941 {
942     PMDL Mdl;
943     PVOID CurrentBase, SystemVa, BaseAddress;
944     PIO_STACK_LOCATION IoStackLocation;
945     LARGE_INTEGER CurrentOffset;
946     ULONG BytesRead, BytesLeft, CopyLength;
947     PVOID Source, Destination;
948     NTSTATUS Status;
949 
950     /* Get the MDL and check if it's mapped */
951     Mdl = Irp->MdlAddress;
952     if (Mdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA | MDL_SOURCE_IS_NONPAGED_POOL))
953     {
954         /* Use the mapped address */
955         SystemVa = Mdl->MappedSystemVa;
956     }
957     else
958     {
959         /* Map it ourselves */
960         SystemVa = MmMapLockedPagesSpecifyCache(Mdl,
961                                                 0,
962                                                 MmCached,
963                                                 NULL,
964                                                 0,
965                                                 NormalPagePriority);
966     }
967 
968     /* Make sure we were able to map it */
969     CurrentBase = SystemVa;
970     if (!SystemVa) return STATUS_INSUFFICIENT_RESOURCES;
971 
972     /* Initialize default */
973     Irp->IoStatus.Information = 0;
974 
975     /* Get the I/O Stack Location and capture the data */
976     IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
977     CurrentOffset = IoStackLocation->Parameters.Read.ByteOffset;
978     BytesLeft = IoStackLocation->Parameters.Read.Length;
979     if (!BytesLeft) return STATUS_INVALID_PARAMETER;
980 
981     /* Do the copy loop */
982     while (TRUE)
983     {
984         /* Map the pages */
985         BaseAddress = RamdiskMapPages(DeviceExtension,
986                                       CurrentOffset,
987                                       BytesLeft,
988                                       &BytesRead);
989         if (!BaseAddress) return STATUS_INSUFFICIENT_RESOURCES;
990 
991         /* Update our lengths */
992         Irp->IoStatus.Information += BytesRead;
993         CopyLength = BytesRead;
994 
995         /* Check if this was a read or write */
996         Status = STATUS_SUCCESS;
997         if (IoStackLocation->MajorFunction == IRP_MJ_READ)
998         {
999             /* Set our copy parameters */
1000             Destination = CurrentBase;
1001             Source = BaseAddress;
1002             goto DoCopy;
1003         }
1004         else if (IoStackLocation->MajorFunction == IRP_MJ_WRITE)
1005         {
1006             /* Set our copy parameters */
1007             Destination = BaseAddress;
1008             Source = CurrentBase;
1009 DoCopy:
1010             /* Copy the data */
1011             RtlCopyMemory(Destination, Source, CopyLength);
1012         }
1013         else
1014         {
1015             /* Prepare us for failure */
1016             BytesLeft = CopyLength;
1017             Status = STATUS_INVALID_PARAMETER;
1018         }
1019 
1020         /* Unmap the pages */
1021         RamdiskUnmapPages(DeviceExtension, BaseAddress, CurrentOffset, BytesRead);
1022 
1023         /* Update offset and bytes left */
1024         BytesLeft -= BytesRead;
1025         CurrentOffset.QuadPart += BytesRead;
1026         CurrentBase = (PVOID)((ULONG_PTR)CurrentBase + BytesRead);
1027 
1028         /* Check if we are done */
1029         if (!BytesLeft) return Status;
1030     }
1031 }
1032 
1033 NTSTATUS
1034 NTAPI
1035 RamdiskOpenClose(IN PDEVICE_OBJECT DeviceObject,
1036                  IN PIRP Irp)
1037 {
1038     /* Complete the IRP */
1039     Irp->IoStatus.Information = 1;
1040     Irp->IoStatus.Status = STATUS_SUCCESS;
1041     IoCompleteRequest(Irp, IO_NO_INCREMENT);
1042     return STATUS_SUCCESS;
1043 }
1044 
1045 NTSTATUS
1046 NTAPI
1047 RamdiskReadWrite(IN PDEVICE_OBJECT DeviceObject,
1048                  IN PIRP Irp)
1049 {
1050     PRAMDISK_DRIVE_EXTENSION DeviceExtension;
1051     // ULONG Length;
1052     // LARGE_INTEGER ByteOffset;
1053     PIO_STACK_LOCATION IoStackLocation;
1054     NTSTATUS Status, ReturnStatus;
1055 
1056     /* Get the device extension and make sure this isn't a bus */
1057     DeviceExtension = DeviceObject->DeviceExtension;
1058     if (DeviceExtension->Type == RamdiskBus)
1059     {
1060         /* Fail */
1061         Status = STATUS_INVALID_DEVICE_REQUEST;
1062         goto Complete;
1063     }
1064 
1065     /* Capture parameters */
1066     IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
1067     // Length = IoStackLocation->Parameters.Read.Length;
1068     // ByteOffset = IoStackLocation->Parameters.Read.ByteOffset;
1069 
1070     /* FIXME: Validate offset */
1071 
1072     /* FIXME: Validate sector */
1073 
1074     /* Validate write */
1075     if ((IoStackLocation->MajorFunction == IRP_MJ_WRITE) &&
1076         (DeviceExtension->DiskOptions.Readonly))
1077     {
1078         /* Fail, this is read-only */
1079         Status = STATUS_MEDIA_WRITE_PROTECTED;
1080         goto Complete;
1081     }
1082 
1083     /* See if we want to do this sync or async */
1084     if (DeviceExtension->DiskType > RAMDISK_MEMORY_MAPPED_DISK)
1085     {
1086         /* Do it sync */
1087         Status = RamdiskReadWriteReal(Irp, DeviceExtension);
1088         goto Complete;
1089     }
1090 
1091     /* Queue it to the worker */
1092     Status = SendIrpToThread(DeviceObject, Irp);
1093     ReturnStatus = STATUS_PENDING;
1094 
1095     /* Check if we're pending or not */
1096     if (Status != STATUS_PENDING)
1097     {
1098 Complete:
1099         /* Complete the IRP */
1100         Irp->IoStatus.Status = Status;
1101         IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1102         ReturnStatus = Status;
1103     }
1104 
1105     /* Return to caller */
1106     return ReturnStatus;
1107 }
1108 
1109 NTSTATUS
1110 NTAPI
1111 RamdiskDeviceControl(IN PDEVICE_OBJECT DeviceObject,
1112                      IN PIRP Irp)
1113 {
1114     NTSTATUS Status;
1115     PIO_STACK_LOCATION IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
1116     PRAMDISK_BUS_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
1117     PRAMDISK_DRIVE_EXTENSION DriveExtension = (PVOID)DeviceExtension;
1118     ULONG Information;
1119     PCDROM_TOC Toc;
1120     PDISK_GEOMETRY DiskGeometry;
1121 
1122     /* Grab the remove lock */
1123     Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Irp);
1124     if (!NT_SUCCESS(Status))
1125     {
1126         /* Fail the IRP */
1127         Irp->IoStatus.Information = 0;
1128         Irp->IoStatus.Status = Status;
1129         IoCompleteRequest(Irp, IO_NO_INCREMENT);
1130         return Status;
1131     }
1132 
1133     /* Setup some defaults */
1134     Status = STATUS_INVALID_DEVICE_REQUEST;
1135     Information = 0;
1136 
1137     /* Check if this is an bus device or the drive */
1138     if (DeviceExtension->Type == RamdiskBus)
1139     {
1140         /* Check what the request is */
1141         switch (IoStackLocation->Parameters.DeviceIoControl.IoControlCode)
1142         {
1143             /* Request to create a ramdisk */
1144             case FSCTL_CREATE_RAM_DISK:
1145             {
1146                 /* Do it */
1147                 Status = RamdiskCreateRamdisk(DeviceObject, Irp, TRUE);
1148                 if (!NT_SUCCESS(Status)) goto CompleteRequest;
1149                 break;
1150             }
1151 
1152             default:
1153             {
1154                 /* We don't handle anything else yet */
1155                 UNIMPLEMENTED_DBGBREAK("FSCTL: 0x%lx is UNSUPPORTED!\n",
1156                                        IoStackLocation->Parameters.DeviceIoControl.IoControlCode);
1157             }
1158         }
1159     }
1160     else
1161     {
1162         /* Check what the request is */
1163         switch (IoStackLocation->Parameters.DeviceIoControl.IoControlCode)
1164         {
1165             case IOCTL_DISK_CHECK_VERIFY:
1166             case IOCTL_STORAGE_CHECK_VERIFY:
1167             case IOCTL_STORAGE_CHECK_VERIFY2:
1168             case IOCTL_CDROM_CHECK_VERIFY:
1169             {
1170                 /* Just pretend it's OK, don't do more */
1171                 Status = STATUS_SUCCESS;
1172                 break;
1173             }
1174 
1175             case IOCTL_STORAGE_GET_MEDIA_TYPES:
1176             case IOCTL_DISK_GET_MEDIA_TYPES:
1177             case IOCTL_DISK_GET_DRIVE_GEOMETRY:
1178             case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
1179             {
1180                 /* Validate the length */
1181                 if (IoStackLocation->Parameters.DeviceIoControl.
1182                     OutputBufferLength < sizeof(DISK_GEOMETRY))
1183                 {
1184                     /* Invalid length */
1185                     Status = STATUS_BUFFER_TOO_SMALL;
1186                     break;
1187                 }
1188 
1189                 /* Fill it out */
1190                 DiskGeometry = Irp->AssociatedIrp.SystemBuffer;
1191                 DiskGeometry->Cylinders.QuadPart = DriveExtension->Cylinders;
1192                 DiskGeometry->BytesPerSector = DriveExtension->BytesPerSector;
1193                 DiskGeometry->SectorsPerTrack = DriveExtension->SectorsPerTrack;
1194                 DiskGeometry->TracksPerCylinder = DriveExtension->NumberOfHeads;
1195                 DiskGeometry->MediaType = DriveExtension->DiskOptions.Fixed ?
1196                                           FixedMedia : RemovableMedia;
1197 
1198                 /* We are done */
1199                 Status = STATUS_SUCCESS;
1200                 Information = sizeof(DISK_GEOMETRY);
1201                 break;
1202             }
1203 
1204             case IOCTL_CDROM_READ_TOC:
1205             {
1206                 /* Validate the length */
1207                 if (IoStackLocation->Parameters.DeviceIoControl.
1208                     OutputBufferLength < sizeof(CDROM_TOC))
1209                 {
1210                     /* Invalid length */
1211                     Status = STATUS_BUFFER_TOO_SMALL;
1212                     break;
1213                 }
1214 
1215                 /* Clear the TOC */
1216                 Toc = Irp->AssociatedIrp.SystemBuffer;
1217                 RtlZeroMemory(Toc, sizeof(CDROM_TOC));
1218 
1219                 /* Fill it out */
1220                 Toc->Length[0] = 0;
1221                 Toc->Length[1] = RAMDISK_TOC_SIZE - sizeof(Toc->Length);
1222                 Toc->FirstTrack = 1;
1223                 Toc->LastTrack = 1;
1224                 Toc->TrackData[0].Adr = 1;
1225                 Toc->TrackData[0].Control = TOC_DATA_TRACK;
1226                 Toc->TrackData[0].TrackNumber = 1;
1227 
1228                 /* We are done */
1229                 Status = STATUS_SUCCESS;
1230                 Information = RAMDISK_TOC_SIZE;
1231                 break;
1232             }
1233 
1234             case IOCTL_DISK_SET_PARTITION_INFO:
1235             {
1236                 Status = RamdiskSetPartitionInfo(Irp, DriveExtension);
1237                 break;
1238             }
1239 
1240             case IOCTL_DISK_GET_PARTITION_INFO:
1241             {
1242                 /* Validate the length */
1243                 if (IoStackLocation->Parameters.DeviceIoControl.
1244                     OutputBufferLength < sizeof(PARTITION_INFORMATION))
1245                 {
1246                     /* Invalid length */
1247                     Status = STATUS_BUFFER_TOO_SMALL;
1248                     break;
1249                 }
1250 
1251                 /* Check if we need to do this sync or async */
1252                 if (DriveExtension->DiskType > RAMDISK_MEMORY_MAPPED_DISK)
1253                 {
1254                     /* Call the helper function */
1255                     Status = RamdiskGetPartitionInfo(Irp, DriveExtension);
1256                 }
1257                 else
1258                 {
1259                     /* Do it asynchronously later */
1260                     goto CallWorker;
1261                 }
1262 
1263                 /* We are done */
1264                 Information = Irp->IoStatus.Information;
1265                 break;
1266             }
1267 
1268             case IOCTL_DISK_GET_LENGTH_INFO:
1269             {
1270                 PGET_LENGTH_INFORMATION LengthInformation = Irp->AssociatedIrp.SystemBuffer;
1271 
1272                 /* Validate the length */
1273                 if (IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GET_LENGTH_INFORMATION))
1274                 {
1275                     /* Invalid length */
1276                     Status = STATUS_BUFFER_TOO_SMALL;
1277                     break;
1278                 }
1279 
1280                 /* Fill it out */
1281                 LengthInformation->Length = DriveExtension->DiskLength;
1282 
1283                 /* We are done */
1284                 Status = STATUS_SUCCESS;
1285                 Information = sizeof(GET_LENGTH_INFORMATION);
1286                 break;
1287             }
1288             case IOCTL_VOLUME_GET_GPT_ATTRIBUTES:
1289             {
1290                 PVOLUME_GET_GPT_ATTRIBUTES_INFORMATION GptInformation;
1291 
1292                 /* Validate the length */
1293                 if (IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength < sizeof(VOLUME_GET_GPT_ATTRIBUTES_INFORMATION))
1294                 {
1295                     /* Invalid length */
1296                     Status = STATUS_BUFFER_TOO_SMALL;
1297                     break;
1298                 }
1299 
1300                 /* Fill it out */
1301                 GptInformation = Irp->AssociatedIrp.SystemBuffer;
1302                 GptInformation->GptAttributes = 0;
1303 
1304                 /* Translate the Attributes */
1305                 if (DriveExtension->DiskOptions.Readonly)
1306                     GptInformation->GptAttributes |= GPT_BASIC_DATA_ATTRIBUTE_READ_ONLY;
1307                 if (DriveExtension->DiskOptions.Hidden)
1308                     GptInformation->GptAttributes |= GPT_BASIC_DATA_ATTRIBUTE_HIDDEN;
1309                 if (DriveExtension->DiskOptions.NoDriveLetter)
1310                     GptInformation->GptAttributes |= GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER;
1311 
1312                 /* We are done */
1313                 Status = STATUS_SUCCESS;
1314                 Information = sizeof(VOLUME_GET_GPT_ATTRIBUTES_INFORMATION);
1315                 break;
1316             }
1317 
1318             case IOCTL_DISK_GET_DRIVE_LAYOUT:
1319             case IOCTL_DISK_IS_WRITABLE:
1320             case IOCTL_SCSI_MINIPORT:
1321             case IOCTL_STORAGE_QUERY_PROPERTY:
1322             case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID:
1323             case IOCTL_MOUNTDEV_QUERY_STABLE_GUID:
1324             case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS:
1325             case IOCTL_VOLUME_SET_GPT_ATTRIBUTES:
1326             case IOCTL_VOLUME_OFFLINE:
1327             {
1328                 UNIMPLEMENTED_DBGBREAK("IOCTL: 0x%lx is UNIMPLEMENTED!\n",
1329                                        IoStackLocation->Parameters.DeviceIoControl.IoControlCode);
1330                 break;
1331             }
1332 
1333             default:
1334             {
1335                 /* Drive code not emulated */
1336                 DPRINT1("IOCTL: 0x%lx is UNSUPPORTED!\n",
1337                         IoStackLocation->Parameters.DeviceIoControl.IoControlCode);
1338                 break;
1339             }
1340         }
1341 
1342         /* If requests drop down here, we just return them complete them */
1343         goto CompleteRequest;
1344     }
1345 
1346     /* Queue the request to our worker thread */
1347 CallWorker:
1348     Status = SendIrpToThread(DeviceObject, Irp);
1349 
1350 CompleteRequest:
1351     /* Release the lock */
1352     IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp);
1353     if (Status != STATUS_PENDING)
1354     {
1355         /* Complete the request */
1356         Irp->IoStatus.Status = Status;
1357         Irp->IoStatus.Information = Information;
1358         IoCompleteRequest(Irp, IO_NO_INCREMENT);
1359     }
1360 
1361     /* Return status */
1362     return Status;
1363 }
1364 
1365 NTSTATUS
1366 NTAPI
1367 RamdiskQueryDeviceRelations(IN DEVICE_RELATION_TYPE Type,
1368                             IN PDEVICE_OBJECT DeviceObject,
1369                             IN PIRP Irp)
1370 {
1371     PRAMDISK_BUS_EXTENSION DeviceExtension;
1372     PRAMDISK_DRIVE_EXTENSION DriveExtension;
1373     PDEVICE_RELATIONS DeviceRelations, OurDeviceRelations;
1374     ULONG Count, DiskCount, FinalCount;
1375     PLIST_ENTRY ListHead, NextEntry;
1376     PDEVICE_OBJECT* DriveDeviceObject;
1377     RAMDISK_DEVICE_STATE State;
1378 
1379     /* Get the device extension and check if this is a drive */
1380     DeviceExtension = DeviceObject->DeviceExtension;
1381     if (DeviceExtension->Type == RamdiskDrive)
1382     {
1383         NTSTATUS Status;
1384         PDEVICE_RELATIONS DeviceRelations;
1385 
1386         /* We're a child device, only handle target device relations */
1387         if (Type != TargetDeviceRelation)
1388         {
1389             Status = Irp->IoStatus.Status;
1390             IoCompleteRequest(Irp, IO_NO_INCREMENT);
1391             return Status;
1392         }
1393 
1394         /* Allocate a buffer big enough to contain only one DO */
1395         DeviceRelations = ExAllocatePoolWithTag(PagedPool,
1396                                                 sizeof(*DeviceRelations),
1397                                                 'dmaR');
1398         if (DeviceRelations != NULL)
1399         {
1400             /* Reference the DO and add it to the buffer */
1401             ObReferenceObject(DeviceObject);
1402             DeviceRelations->Objects[0] = DeviceObject;
1403             DeviceRelations->Count = 1;
1404             Status = STATUS_SUCCESS;
1405         }
1406         else
1407         {
1408             Status = STATUS_INSUFFICIENT_RESOURCES;
1409         }
1410 
1411         /* Return our processing & complete */
1412         Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
1413         Irp->IoStatus.Status = Status;
1414         IoCompleteRequest(Irp, IO_NO_INCREMENT);
1415         return Status;
1416     }
1417 
1418     /* We don't handle anything but bus relations */
1419     if (Type != BusRelations) goto PassToNext;
1420 
1421     /* Acquire the disk list lock */
1422     KeEnterCriticalRegion();
1423     ExAcquireFastMutex(&DeviceExtension->DiskListLock);
1424 
1425     /* Did a device already fill relations? */
1426     DeviceRelations = (PDEVICE_RELATIONS)Irp->IoStatus.Information;
1427     if (DeviceRelations)
1428     {
1429         /* Use the data */
1430         Count = DeviceRelations->Count;
1431     }
1432     else
1433     {
1434         /* We're the first */
1435         Count = 0;
1436     }
1437 
1438     /* Now loop our drives */
1439     DiskCount = 0;
1440     ListHead = &DeviceExtension->DiskList;
1441     NextEntry = ListHead->Flink;
1442     while (NextEntry != ListHead)
1443     {
1444         /* As long as it wasn't removed, count it in */
1445         DriveExtension = CONTAINING_RECORD(NextEntry,
1446                                            RAMDISK_DRIVE_EXTENSION,
1447                                            DiskList);
1448         if (DriveExtension->State < RamdiskStateBusRemoved) DiskCount++;
1449 
1450         /* Move to the next one */
1451         NextEntry = NextEntry->Flink;
1452     }
1453 
1454     /* Now we know our final count */
1455     FinalCount = Count + DiskCount;
1456 
1457     /* Allocate the structure */
1458     OurDeviceRelations = ExAllocatePoolWithTag(PagedPool,
1459                                                FIELD_OFFSET(DEVICE_RELATIONS,
1460                                                             Objects) +
1461                                                FinalCount *
1462                                                sizeof(PDEVICE_OBJECT),
1463                                                'dmaR');
1464     if (!OurDeviceRelations)
1465     {
1466         /* Fail */
1467         ExReleaseFastMutex(&DeviceExtension->DiskListLock);
1468         KeLeaveCriticalRegion();
1469         Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1470         IoCompleteRequest(Irp, IO_NO_INCREMENT);
1471         return STATUS_INSUFFICIENT_RESOURCES;
1472     }
1473 
1474     /* Check if we already had some relations */
1475     if (Count)
1476     {
1477         /* Copy them in */
1478         RtlCopyMemory(OurDeviceRelations->Objects,
1479                       DeviceRelations->Objects,
1480                       Count * sizeof(PDEVICE_OBJECT));
1481     }
1482 
1483     /* Save the count */
1484     OurDeviceRelations->Count = FinalCount;
1485 
1486     /* Now loop our drives again */
1487     ListHead = &DeviceExtension->DiskList;
1488     NextEntry = ListHead->Flink;
1489     while (NextEntry != ListHead)
1490     {
1491         /* Go to the end of the list */
1492         DriveDeviceObject = &OurDeviceRelations->Objects[Count];
1493 
1494         /* Get the drive state */
1495         DriveExtension = CONTAINING_RECORD(NextEntry,
1496                                            RAMDISK_DRIVE_EXTENSION,
1497                                            DiskList);
1498         State = DriveExtension->State;
1499 
1500         /* If it was removed or enumerated, we don't touch the device object */
1501         if (State >= RamdiskStateBusRemoved)
1502         {
1503             /* If it was removed, we still have to keep track of this though */
1504             if (State == RamdiskStateBusRemoved)
1505             {
1506                 /* Mark it as enumerated now, but don't actually reference it */
1507                 DriveExtension->State = RamdiskStateEnumerated;
1508             }
1509         }
1510         else
1511         {
1512             /* First time it's enumerated, reference the device object */
1513             ObReferenceObject(DriveExtension->DeviceObject);
1514 
1515             /* Save the object pointer and move on */
1516             *DriveDeviceObject++ = DriveExtension->PhysicalDeviceObject;
1517         }
1518 
1519         if (DriveExtension->State < RamdiskStateBusRemoved) DiskCount++;
1520 
1521         /* Move to the next one */
1522         NextEntry = NextEntry->Flink;
1523     }
1524 
1525     /* Release the lock */
1526     ExReleaseFastMutex(&DeviceExtension->DiskListLock);
1527     KeLeaveCriticalRegion();
1528 
1529     /* Cleanup old relations */
1530     if (DeviceRelations) ExFreePool(DeviceRelations);
1531 
1532     /* Complete our IRP */
1533     Irp->IoStatus.Information = (ULONG_PTR)OurDeviceRelations;
1534     Irp->IoStatus.Status = STATUS_SUCCESS;
1535 
1536     /* Pass to the next driver */
1537 PassToNext:
1538     IoCopyCurrentIrpStackLocationToNext(Irp);
1539     return IoCallDriver(DeviceExtension->AttachedDevice, Irp);
1540 }
1541 
1542 NTSTATUS
1543 NTAPI
1544 RamdiskDeleteDiskDevice(IN PDEVICE_OBJECT DeviceObject,
1545                         IN PIRP Irp)
1546 {
1547     UNIMPLEMENTED_DBGBREAK();
1548     return STATUS_SUCCESS;
1549 }
1550 
1551 NTSTATUS
1552 NTAPI
1553 RamdiskRemoveBusDevice(IN PDEVICE_OBJECT DeviceObject,
1554                        IN PIRP Irp)
1555 {
1556     NTSTATUS Status;
1557     PLIST_ENTRY ListHead, NextEntry;
1558     PRAMDISK_BUS_EXTENSION DeviceExtension;
1559     PRAMDISK_DRIVE_EXTENSION DriveExtension;
1560 
1561     DeviceExtension = DeviceObject->DeviceExtension;
1562 
1563     /* Acquire disks list lock */
1564     KeEnterCriticalRegion();
1565     ExAcquireFastMutex(&DeviceExtension->DiskListLock);
1566 
1567     /* Loop over drives */
1568     ListHead = &DeviceExtension->DiskList;
1569     NextEntry = ListHead->Flink;
1570     while (NextEntry != ListHead)
1571     {
1572         DriveExtension = CONTAINING_RECORD(NextEntry,
1573                                            RAMDISK_DRIVE_EXTENSION,
1574                                            DiskList);
1575 
1576         /* Delete the disk */
1577         IoAcquireRemoveLock(&DriveExtension->RemoveLock, NULL);
1578         RamdiskDeleteDiskDevice(DriveExtension->PhysicalDeviceObject, NULL);
1579 
1580         /* RamdiskDeleteDiskDevice releases list lock, so reacquire it */
1581         KeEnterCriticalRegion();
1582         ExAcquireFastMutex(&DeviceExtension->DiskListLock);
1583     }
1584 
1585     /* Release disks list lock */
1586     ExReleaseFastMutex(&DeviceExtension->DiskListLock);
1587     KeLeaveCriticalRegion();
1588 
1589     /* Prepare to pass to the lower driver */
1590     IoSkipCurrentIrpStackLocation(Irp);
1591     /* Here everything went fine */
1592     Irp->IoStatus.Status = STATUS_SUCCESS;
1593 
1594     /* Call lower driver */
1595     Status = IoCallDriver(DeviceExtension->AttachedDevice, Irp);
1596 
1597     /* Update state */
1598     DeviceExtension->State = RamdiskStateBusRemoved;
1599 
1600     /* Release the lock and ensure that everyone has finished its job before
1601      * we continue. The lock has been acquired by the dispatcher */
1602     IoReleaseRemoveLockAndWait(&DeviceExtension->RemoveLock, Irp);
1603 
1604     /* If there's a drive name */
1605     if (DeviceExtension->DriveDeviceName.Buffer)
1606     {
1607         /* Inform it's going to be disabled and free the drive name */
1608         IoSetDeviceInterfaceState(&DeviceExtension->DriveDeviceName, FALSE);
1609         RtlFreeUnicodeString(&DeviceExtension->DriveDeviceName);
1610     }
1611 
1612     /* Part from the stack, detach from lower device */
1613     IoDetachDevice(DeviceExtension->AttachedDevice);
1614 
1615     /* Finally, delete device */
1616     RamdiskBusFdo = NULL;
1617     IoDeleteDevice(DeviceObject);
1618 
1619     /* Return status from lower driver */
1620     return Status;
1621 }
1622 
1623 NTSTATUS
1624 NTAPI
1625 RamdiskQueryId(IN PRAMDISK_DRIVE_EXTENSION DriveExtension,
1626                IN PIRP Irp)
1627 {
1628     NTSTATUS Status;
1629     PIO_STACK_LOCATION IoStackLocation;
1630     PWSTR OutputString = NULL;
1631     ULONG StringLength;
1632 
1633     Status = STATUS_SUCCESS;
1634     IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
1635 
1636     /* Get what is being queried */
1637     switch (IoStackLocation->Parameters.QueryId.IdType)
1638     {
1639         case BusQueryDeviceID:
1640         {
1641             /* Allocate a buffer long enough to receive Ramdisk\RamDisk in any case
1642              * In case we don't have RAMDISK_REGISTRY_DISK, we then need two more
1643              * chars to store Ramdisk\RamVolume instead */
1644             StringLength = 4 * (DriveExtension->DiskType != RAMDISK_REGISTRY_DISK) + sizeof(L"Ramdisk\\RamDisk");
1645             OutputString = ExAllocatePoolWithTag(PagedPool, StringLength, 'dmaR');
1646             if (OutputString == NULL)
1647             {
1648                 Status = STATUS_INSUFFICIENT_RESOURCES;
1649                 break;
1650             }
1651 
1652             wcsncpy(OutputString, L"Ramdisk\\", StringLength / sizeof(WCHAR));
1653             if (DriveExtension->DiskType != RAMDISK_REGISTRY_DISK)
1654             {
1655                 wcsncat(OutputString, L"RamVolume", StringLength / sizeof(WCHAR));
1656             }
1657             else
1658             {
1659                 wcsncat(OutputString, L"RamDisk", StringLength / sizeof(WCHAR));
1660             }
1661 
1662             break;
1663         }
1664 
1665         case BusQueryHardwareIDs:
1666         {
1667             /* Allocate a buffer long enough to receive Ramdisk\RamDisk in any case
1668              * In case we don't have RAMDISK_REGISTRY_DISK, we then need two more
1669              * chars to store Ramdisk\RamVolume instead
1670              * We also need an extra char, because it is required that the string
1671              * is null-terminated twice */
1672             StringLength = 4 * (DriveExtension->DiskType != RAMDISK_REGISTRY_DISK) +
1673                            sizeof(UNICODE_NULL) + sizeof(L"Ramdisk\\RamDisk");
1674             OutputString = ExAllocatePoolWithTag(PagedPool, StringLength, 'dmaR');
1675             if (OutputString == NULL)
1676             {
1677                 Status = STATUS_INSUFFICIENT_RESOURCES;
1678                 break;
1679             }
1680 
1681             wcsncpy(OutputString, L"Ramdisk\\", StringLength / sizeof(WCHAR));
1682             if (DriveExtension->DiskType != RAMDISK_REGISTRY_DISK)
1683             {
1684                 wcsncat(OutputString, L"RamVolume", StringLength / sizeof(WCHAR));
1685             }
1686             else
1687             {
1688                 wcsncat(OutputString, L"RamDisk", StringLength / sizeof(WCHAR));
1689             }
1690             OutputString[(StringLength / sizeof(WCHAR)) - 1] = UNICODE_NULL;
1691 
1692             break;
1693         }
1694 
1695         case BusQueryCompatibleIDs:
1696         {
1697             if (DriveExtension->DiskType != RAMDISK_REGISTRY_DISK)
1698             {
1699                 Status = STATUS_INVALID_DEVICE_REQUEST;
1700                 break;
1701             }
1702 
1703             StringLength = sizeof(L"GenDisk");
1704             OutputString = ExAllocatePoolWithTag(PagedPool, StringLength, 'dmaR');
1705             if (OutputString == NULL)
1706             {
1707                 Status = STATUS_INSUFFICIENT_RESOURCES;
1708                 break;
1709             }
1710 
1711             wcsncpy(OutputString, L"GenDisk", StringLength / sizeof(WCHAR));
1712             OutputString[(StringLength / sizeof(WCHAR)) - 1] = UNICODE_NULL;
1713 
1714             break;
1715         }
1716 
1717         case BusQueryInstanceID:
1718         {
1719             OutputString = ExAllocatePoolWithTag(PagedPool,
1720                                                  DriveExtension->GuidString.MaximumLength,
1721                                                  'dmaR');
1722             if (OutputString == NULL)
1723             {
1724                 Status = STATUS_INSUFFICIENT_RESOURCES;
1725                 break;
1726             }
1727 
1728             wcsncpy(OutputString,
1729                     DriveExtension->GuidString.Buffer,
1730                     DriveExtension->GuidString.MaximumLength / sizeof(WCHAR));
1731 
1732             break;
1733         }
1734 
1735         case BusQueryDeviceSerialNumber:
1736         {
1737             /* Nothing to do */
1738             break;
1739         }
1740     }
1741 
1742     Irp->IoStatus.Status = Status;
1743     Irp->IoStatus.Information = (ULONG_PTR)OutputString;
1744     IoCompleteRequest(Irp, IO_NO_INCREMENT);
1745     return Status;
1746 }
1747 
1748 NTSTATUS
1749 NTAPI
1750 RamdiskQueryCapabilities(IN PDEVICE_OBJECT DeviceObject,
1751                          IN PIRP Irp)
1752 {
1753     NTSTATUS Status;
1754     PIO_STACK_LOCATION IoStackLocation;
1755     PDEVICE_CAPABILITIES DeviceCapabilities;
1756     PRAMDISK_DRIVE_EXTENSION DriveExtension;
1757 
1758     IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
1759     DeviceCapabilities = IoStackLocation->Parameters.DeviceCapabilities.Capabilities;
1760     DriveExtension = DeviceObject->DeviceExtension;
1761 
1762     /* Validate our input buffer */
1763     if (DeviceCapabilities->Version != 1 ||
1764         DeviceCapabilities->Size < sizeof(DEVICE_CAPABILITIES))
1765     {
1766         Status = STATUS_UNSUCCESSFUL;
1767     }
1768     else
1769     {
1770         /* And set everything we know about our capabilities */
1771         DeviceCapabilities->Removable = MarkRamdisksAsRemovable;
1772         DeviceCapabilities->UniqueID = TRUE;
1773         DeviceCapabilities->SilentInstall = TRUE;
1774         DeviceCapabilities->RawDeviceOK = TRUE;
1775         DeviceCapabilities->SurpriseRemovalOK = (DriveExtension->DiskType != RAMDISK_REGISTRY_DISK);
1776         DeviceCapabilities->NoDisplayInUI = TRUE;
1777         Status = STATUS_SUCCESS;
1778     }
1779 
1780     Irp->IoStatus.Status = Status;
1781     IoCompleteRequest(Irp, IO_NO_INCREMENT);
1782     return Status;
1783 }
1784 
1785 NTSTATUS
1786 NTAPI
1787 RamdiskQueryDeviceText(IN PRAMDISK_DRIVE_EXTENSION DriveExtension,
1788                        IN PIRP Irp)
1789 {
1790     NTSTATUS Status;
1791     PIO_STACK_LOCATION IoStackLocation;
1792     DEVICE_TEXT_TYPE DeviceTextType;
1793     PWSTR OutputString = NULL;
1794 
1795     IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
1796     DeviceTextType = IoStackLocation->Parameters.QueryDeviceText.DeviceTextType;
1797     Status = STATUS_SUCCESS;
1798 
1799     /* Just copy our constants, according to the input */
1800     switch (DeviceTextType)
1801     {
1802         case DeviceTextDescription:
1803         {
1804             OutputString = ExAllocatePoolWithTag(PagedPool, sizeof(L"RamDisk"), 'dmaR');
1805             if (OutputString == NULL)
1806             {
1807                 Status = STATUS_INSUFFICIENT_RESOURCES;
1808                 break;
1809             }
1810 
1811             wcsncpy(OutputString, L"RamDisk", sizeof(L"RamDisk") / sizeof(WCHAR));
1812 
1813             break;
1814         }
1815 
1816         case DeviceTextLocationInformation:
1817         {
1818             OutputString = ExAllocatePoolWithTag(PagedPool, sizeof(L"RamDisk\\0"), 'dmaR');
1819             if (OutputString == NULL)
1820             {
1821                 Status = STATUS_INSUFFICIENT_RESOURCES;
1822                 break;
1823             }
1824 
1825             wcsncpy(OutputString, L"RamDisk\\0", sizeof(L"RamDisk\\0") / sizeof(WCHAR));
1826 
1827             break;
1828         }
1829     }
1830 
1831     Irp->IoStatus.Status = Status;
1832     Irp->IoStatus.Information = (ULONG_PTR)OutputString;
1833     IoCompleteRequest(Irp, IO_NO_INCREMENT);
1834     return Status;
1835 }
1836 
1837 NTSTATUS
1838 NTAPI
1839 RamdiskQueryBusInformation(IN PDEVICE_OBJECT DeviceObject,
1840                            IN PIRP Irp)
1841 {
1842     PPNP_BUS_INFORMATION PnpBusInfo;
1843     NTSTATUS Status = STATUS_SUCCESS;
1844 
1845     /* Allocate output memory */
1846     PnpBusInfo = ExAllocatePoolWithTag(PagedPool, sizeof(*PnpBusInfo), 'dmaR');
1847     if (PnpBusInfo == NULL)
1848     {
1849         Status = STATUS_INSUFFICIENT_RESOURCES;
1850     }
1851     else
1852     {
1853         /* Copy our bus GUID and set our legacy type */
1854         RtlCopyMemory(&PnpBusInfo->BusTypeGuid, &GUID_BUS_TYPE_RAMDISK, sizeof(GUID));
1855         PnpBusInfo->LegacyBusType = PNPBus;
1856         PnpBusInfo->BusNumber = 0;
1857     }
1858 
1859     Irp->IoStatus.Status = Status;
1860     Irp->IoStatus.Information = (ULONG_PTR)PnpBusInfo;
1861     IoCompleteRequest(Irp, IO_NO_INCREMENT);
1862     return Status;
1863 }
1864 
1865 NTSTATUS
1866 NTAPI
1867 RamdiskIoCompletionRoutine(IN PDEVICE_OBJECT DeviceObject,
1868                            IN PIRP Irp,
1869                            IN PVOID Context)
1870 
1871 {
1872     /* Just set the event to unlock caller */
1873     KeSetEvent((PKEVENT)Context, 0, FALSE);
1874 
1875     return STATUS_MORE_PROCESSING_REQUIRED;
1876 }
1877 
1878 NTSTATUS
1879 NTAPI
1880 RamdiskPnp(IN PDEVICE_OBJECT DeviceObject,
1881            IN PIRP Irp)
1882 {
1883     PIO_STACK_LOCATION IoStackLocation;
1884     PRAMDISK_BUS_EXTENSION DeviceExtension;
1885     NTSTATUS Status;
1886     UCHAR Minor;
1887     KEVENT Event;
1888 
1889     /* Get the device extension and stack location */
1890     DeviceExtension = DeviceObject->DeviceExtension;
1891     IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
1892     Minor = IoStackLocation->MinorFunction;
1893 
1894     /* Check if the bus is removed */
1895     if (DeviceExtension->State == RamdiskStateBusRemoved)
1896     {
1897         /* Only remove-device and query-id are allowed */
1898         if ((Minor != IRP_MN_REMOVE_DEVICE) && (Minor != IRP_MN_QUERY_ID))
1899         {
1900             /* Fail anything else */
1901             Status = STATUS_NO_SUCH_DEVICE;
1902             Irp->IoStatus.Status = Status;
1903             IoCompleteRequest(Irp, IO_NO_INCREMENT);
1904             return Status;
1905         }
1906     }
1907 
1908     /* Acquire the remove lock */
1909     Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Irp);
1910     if (!NT_SUCCESS(Status))
1911     {
1912         /* Fail the IRP */
1913         Irp->IoStatus.Information = 0;
1914         Irp->IoStatus.Status = Status;
1915         IoCompleteRequest(Irp, IO_NO_INCREMENT);
1916         return Status;
1917     }
1918 
1919     /* Query the IRP type */
1920     switch (Minor)
1921     {
1922         case IRP_MN_START_DEVICE:
1923         {
1924             if (DeviceExtension->Type == RamdiskDrive)
1925             {
1926                 ULONG ResultLength;
1927                 DEVICE_INSTALL_STATE InstallState;
1928                 PRAMDISK_DRIVE_EXTENSION DriveExtension = (PRAMDISK_DRIVE_EXTENSION)DeviceExtension;
1929 
1930                 /* If we already have a drive name, free it */
1931                 if (DriveExtension->DriveDeviceName.Buffer)
1932                 {
1933                     ExFreePool(DriveExtension->DriveDeviceName.Buffer);
1934                 }
1935 
1936                 /* Register our device interface */
1937                 if (DriveExtension->DiskType != RAMDISK_REGISTRY_DISK)
1938                 {
1939                     Status = IoRegisterDeviceInterface(DeviceObject,
1940                                                        &GUID_DEVINTERFACE_VOLUME,
1941                                                        NULL,
1942                                                        &DriveExtension->DriveDeviceName);
1943                 }
1944                 else
1945                 {
1946                     Status = IoRegisterDeviceInterface(DeviceObject,
1947                                                        &RamdiskDiskInterface,
1948                                                        NULL,
1949                                                        &DriveExtension->DriveDeviceName);
1950                 }
1951 
1952                 /* If we were asked not to assign a drive letter or if getting
1953                  * a name failed, just return saying we're now started */
1954                 if (DriveExtension->DiskOptions.NoDriveLetter ||
1955                     DriveExtension->DriveDeviceName.Buffer == NULL)
1956                 {
1957                     DriveExtension->State = RamdiskStateStarted;
1958                     Irp->IoStatus.Status = Status;
1959                     break;
1960                 }
1961 
1962                 /* Now get our installation state */
1963                 Status = IoGetDeviceProperty(DeviceObject,
1964                                              DevicePropertyInstallState,
1965                                              sizeof(InstallState),
1966                                              &InstallState,
1967                                              &ResultLength);
1968                 /* If querying the information failed, assume success */
1969                 if (!NT_SUCCESS(Status))
1970                 {
1971                     InstallState = InstallStateInstalled;
1972                 }
1973 
1974                 /* If we were properly installed, then, enable the interface */
1975                 if (InstallState == InstallStateInstalled)
1976                 {
1977                     Status = IoSetDeviceInterfaceState(&DriveExtension->DriveDeviceName, TRUE);
1978                 }
1979 
1980                 /* We're fine & up */
1981                 DriveExtension->State = RamdiskStateStarted;
1982                 Irp->IoStatus.Status = Status;
1983                 break;
1984             }
1985 
1986             /* Prepare next stack to pass it down */
1987             IoCopyCurrentIrpStackLocationToNext(Irp);
1988 
1989             /* Initialize our notification event & our completion routine */
1990             KeInitializeEvent(&Event, NotificationEvent, FALSE);
1991             IoSetCompletionRoutine(Irp, RamdiskIoCompletionRoutine, &Event, TRUE, TRUE, TRUE);
1992 
1993             /* Call lower driver */
1994             Status = IoCallDriver(DeviceExtension->AttachedDevice, Irp);
1995             if (Status == STATUS_PENDING)
1996             {
1997                 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1998                 Status = Irp->IoStatus.Status;
1999             }
2000 
2001             /* If it succeed to start then enable ourselves and we're up! */
2002             if (NT_SUCCESS(Status))
2003             {
2004                 Status = IoSetDeviceInterfaceState(&DeviceExtension->DriveDeviceName, TRUE);
2005                 DeviceExtension->State = RamdiskStateStarted;
2006             }
2007 
2008             Irp->IoStatus.Status = Status;
2009             break;
2010         }
2011 
2012         case IRP_MN_QUERY_STOP_DEVICE:
2013         case IRP_MN_CANCEL_STOP_DEVICE:
2014         case IRP_MN_STOP_DEVICE:
2015         case IRP_MN_QUERY_REMOVE_DEVICE:
2016         case IRP_MN_CANCEL_REMOVE_DEVICE:
2017         {
2018             UNIMPLEMENTED_DBGBREAK("PnP IRP: %lx\n", Minor);
2019             break;
2020         }
2021 
2022         case IRP_MN_REMOVE_DEVICE:
2023         {
2024             /* Remove the proper device */
2025             if (DeviceExtension->Type == RamdiskBus)
2026             {
2027                 Status = RamdiskRemoveBusDevice(DeviceObject, Irp);
2028 
2029                 /* Return here, lower device has already been called
2030                  * And remove lock released. This is needed by the function. */
2031                 return Status;
2032             }
2033             else
2034             {
2035                 Status = RamdiskDeleteDiskDevice(DeviceObject, Irp);
2036 
2037                 /* Complete the IRP here and return
2038                  * Here again we don't have to release remove lock
2039                  * This has already been done by the function. */
2040                 Irp->IoStatus.Status = Status;
2041                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2042                 return Status;
2043             }
2044         }
2045 
2046         case IRP_MN_SURPRISE_REMOVAL:
2047             UNIMPLEMENTED_DBGBREAK("PnP IRP: %lx\n", Minor);
2048             break;
2049 
2050         case IRP_MN_QUERY_ID:
2051         {
2052             /* Are we a drive? */
2053             if (DeviceExtension->Type == RamdiskDrive)
2054             {
2055                 Status = RamdiskQueryId((PRAMDISK_DRIVE_EXTENSION)DeviceExtension, Irp);
2056             }
2057             break;
2058         }
2059 
2060         case IRP_MN_QUERY_BUS_INFORMATION:
2061         {
2062             /* Are we a drive? */
2063             if (DeviceExtension->Type == RamdiskDrive)
2064             {
2065                 Status = RamdiskQueryBusInformation(DeviceObject, Irp);
2066             }
2067             break;
2068         }
2069 
2070         case IRP_MN_EJECT:
2071             UNIMPLEMENTED_DBGBREAK("PnP IRP: %lx\n", Minor);
2072             break;
2073 
2074         case IRP_MN_QUERY_DEVICE_TEXT:
2075         {
2076             /* Are we a drive? */
2077             if (DeviceExtension->Type == RamdiskDrive)
2078             {
2079                 Status = RamdiskQueryDeviceText((PRAMDISK_DRIVE_EXTENSION)DeviceExtension, Irp);
2080             }
2081             break;
2082         }
2083 
2084         case IRP_MN_QUERY_DEVICE_RELATIONS:
2085         {
2086             /* Call our main routine */
2087             Status = RamdiskQueryDeviceRelations(IoStackLocation->
2088                                                  Parameters.
2089                                                  QueryDeviceRelations.Type,
2090                                                  DeviceObject,
2091                                                  Irp);
2092             goto ReleaseAndReturn;
2093         }
2094 
2095         case IRP_MN_QUERY_CAPABILITIES:
2096         {
2097             /* Are we a drive? */
2098             if (DeviceExtension->Type == RamdiskDrive)
2099             {
2100                 Status = RamdiskQueryCapabilities(DeviceObject, Irp);
2101             }
2102             break;
2103         }
2104 
2105         case IRP_MN_QUERY_RESOURCES:
2106         case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
2107         {
2108             /* Complete immediately without touching it */
2109             IoCompleteRequest(Irp, IO_NO_INCREMENT);
2110             goto ReleaseAndReturn;
2111         }
2112 
2113         default:
2114             DPRINT1("Illegal IRP: %lx\n", Minor);
2115             break;
2116     }
2117 
2118     /* Are we the bus? */
2119     if (DeviceExtension->Type == RamdiskBus)
2120     {
2121         /* Do we have an attached device? */
2122         if (DeviceExtension->AttachedDevice)
2123         {
2124             /* Forward the IRP */
2125             IoSkipCurrentIrpStackLocation(Irp);
2126             Status = IoCallDriver(DeviceExtension->AttachedDevice, Irp);
2127         }
2128     }
2129 
2130     /* Release the lock and return status */
2131 ReleaseAndReturn:
2132     IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp);
2133     return Status;
2134 }
2135 
2136 NTSTATUS
2137 NTAPI
2138 RamdiskPower(IN PDEVICE_OBJECT DeviceObject,
2139              IN PIRP Irp)
2140 {
2141     NTSTATUS Status;
2142     PIO_STACK_LOCATION IoStackLocation;
2143     PRAMDISK_BUS_EXTENSION DeviceExtension;
2144 
2145     DeviceExtension = DeviceObject->DeviceExtension;
2146 
2147     /* If we have a device extension, take extra caution with the lower driver */
2148     if (DeviceExtension != NULL)
2149     {
2150         PoStartNextPowerIrp(Irp);
2151 
2152         /* Device has not been removed yet, so pass to the attached/lower driver */
2153         if (DeviceExtension->State < RamdiskStateBusRemoved)
2154         {
2155             IoSkipCurrentIrpStackLocation(Irp);
2156             return PoCallDriver(DeviceExtension->AttachedDevice, Irp);
2157         }
2158         /* Otherwise, simply complete the IRP notifying that deletion is pending */
2159         else
2160         {
2161             Irp->IoStatus.Status = STATUS_DELETE_PENDING;
2162             IoCompleteRequest(Irp, IO_NO_INCREMENT);
2163             return STATUS_DELETE_PENDING;
2164         }
2165     }
2166 
2167     /* Get stack and deal with minor functions */
2168     IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
2169     switch (IoStackLocation->MinorFunction)
2170     {
2171         case IRP_MN_SET_POWER:
2172         {
2173             /* If setting device power state it's all fine and return success */
2174             if (DevicePowerState)
2175             {
2176                 Irp->IoStatus.Status = STATUS_SUCCESS;
2177             }
2178 
2179             /* Get appropriate status for return */
2180             Status = Irp->IoStatus.Status;
2181             PoStartNextPowerIrp(Irp);
2182             IoCompleteRequest(Irp, IO_NO_INCREMENT);
2183             break;
2184         }
2185 
2186         case IRP_MN_QUERY_POWER:
2187         {
2188             /* We can obviously accept all states so just return success */
2189             Status = Irp->IoStatus.Status = STATUS_SUCCESS;
2190             PoStartNextPowerIrp(Irp);
2191             IoCompleteRequest(Irp, IO_NO_INCREMENT);
2192             break;
2193         }
2194 
2195         default:
2196         {
2197             /* Just complete and save status for return */
2198             Status = Irp->IoStatus.Status;
2199             PoStartNextPowerIrp(Irp);
2200             IoCompleteRequest(Irp, IO_NO_INCREMENT);
2201             break;
2202         }
2203     }
2204 
2205     return Status;
2206 }
2207 
2208 NTSTATUS
2209 NTAPI
2210 RamdiskSystemControl(IN PDEVICE_OBJECT DeviceObject,
2211                      IN PIRP Irp)
2212 {
2213     NTSTATUS Status;
2214     PRAMDISK_BUS_EXTENSION DeviceExtension;
2215 
2216     DeviceExtension = DeviceObject->DeviceExtension;
2217 
2218     /* If we have a device extension, forward the IRP to the attached device */
2219     if (DeviceExtension != NULL)
2220     {
2221         IoSkipCurrentIrpStackLocation(Irp);
2222         Status = IoCallDriver(DeviceExtension->AttachedDevice, Irp);
2223     }
2224     /* Otherwise just complete the request
2225      * And return the status with which we complete it */
2226     else
2227     {
2228         Status = Irp->IoStatus.Status;
2229         IoCompleteRequest(Irp, IO_NO_INCREMENT);
2230     }
2231 
2232     return Status;
2233 }
2234 
2235 NTSTATUS
2236 NTAPI
2237 RamdiskScsi(IN PDEVICE_OBJECT DeviceObject,
2238             IN PIRP Irp)
2239 {
2240     NTSTATUS Status;
2241     PRAMDISK_BUS_EXTENSION DeviceExtension;
2242 
2243     DeviceExtension = DeviceObject->DeviceExtension;
2244 
2245     /* Having a proper device is mandatory */
2246     if (DeviceExtension->State > RamdiskStateStopped)
2247     {
2248         Status = STATUS_DEVICE_DOES_NOT_EXIST;
2249         goto CompleteIRP;
2250     }
2251 
2252     /* Acquire the remove lock */
2253     Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Irp);
2254     if (!NT_SUCCESS(Status))
2255     {
2256         goto CompleteIRP;
2257     }
2258 
2259     /* Queue the IRP for worker */
2260     Status = SendIrpToThread(DeviceObject, Irp);
2261     if (Status != STATUS_PENDING)
2262     {
2263         goto CompleteIRP;
2264     }
2265 
2266     /* Release the remove lock */
2267     IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp);
2268     goto Quit;
2269 
2270 CompleteIRP:
2271     Irp->IoStatus.Information = 0;
2272     Irp->IoStatus.Status = Status;
2273     IoCompleteRequest(Irp, IO_NO_INCREMENT);
2274 
2275 Quit:
2276     return Status;
2277 }
2278 
2279 NTSTATUS
2280 NTAPI
2281 RamdiskFlushBuffers(IN PDEVICE_OBJECT DeviceObject,
2282                     IN PIRP Irp)
2283 {
2284     NTSTATUS Status;
2285     PRAMDISK_DRIVE_EXTENSION DeviceExtension;
2286 
2287     DeviceExtension = DeviceObject->DeviceExtension;
2288 
2289     /* Ensure we have drive extension
2290      * Only perform flush on disks that have been created
2291      * from registry entries */
2292     if (DeviceExtension->Type != RamdiskDrive ||
2293         DeviceExtension->DiskType > RAMDISK_MEMORY_MAPPED_DISK)
2294     {
2295         Irp->IoStatus.Information = 0;
2296         Irp->IoStatus.Status = STATUS_SUCCESS;
2297         IoCompleteRequest(Irp, IO_NO_INCREMENT);
2298         return STATUS_SUCCESS;
2299     }
2300 
2301     /* Queue the IRP for worker */
2302     Status = SendIrpToThread(DeviceObject, Irp);
2303     if (Status != STATUS_PENDING)
2304     {
2305         /* Queuing failed - complete the IRP and return failure */
2306         Irp->IoStatus.Information = 0;
2307         Irp->IoStatus.Status = Status;
2308         IoCompleteRequest(Irp, IO_NO_INCREMENT);
2309     }
2310 
2311     return Status;
2312 }
2313 
2314 VOID
2315 NTAPI
2316 RamdiskUnload(IN PDRIVER_OBJECT DriverObject)
2317 {
2318     /* Just release registry path if previously allocated */
2319     if (DriverRegistryPath.Buffer)
2320     {
2321         ExFreePoolWithTag(DriverRegistryPath.Buffer, 'dmaR');
2322     }
2323 }
2324 
2325 NTSTATUS
2326 NTAPI
2327 RamdiskAddDevice(IN PDRIVER_OBJECT DriverObject,
2328                  IN PDEVICE_OBJECT PhysicalDeviceObject)
2329 {
2330     PRAMDISK_BUS_EXTENSION DeviceExtension;
2331     PDEVICE_OBJECT AttachedDevice;
2332     NTSTATUS Status;
2333     UNICODE_STRING DeviceName;
2334     PDEVICE_OBJECT DeviceObject;
2335 
2336     /* Only create the bus FDO once */
2337     if (RamdiskBusFdo) return STATUS_DEVICE_ALREADY_ATTACHED;
2338 
2339     /* Create the bus FDO */
2340     RtlInitUnicodeString(&DeviceName, L"\\Device\\Ramdisk");
2341     Status = IoCreateDevice(DriverObject,
2342                             sizeof(RAMDISK_BUS_EXTENSION),
2343                             &DeviceName,
2344                             FILE_DEVICE_BUS_EXTENDER,
2345                             FILE_DEVICE_SECURE_OPEN,
2346                             0,
2347                             &DeviceObject);
2348     if (NT_SUCCESS(Status))
2349     {
2350         /* Initialize the bus FDO extension */
2351         DeviceExtension = DeviceObject->DeviceExtension;
2352         RtlZeroMemory(DeviceExtension, sizeof(*DeviceExtension));
2353 
2354         /* Set bus FDO flags */
2355         DeviceObject->Flags |= DO_POWER_PAGABLE | DO_DIRECT_IO;
2356 
2357         /* Setup the bus FDO extension */
2358         DeviceExtension->Type = RamdiskBus;
2359         ExInitializeFastMutex(&DeviceExtension->DiskListLock);
2360         IoInitializeRemoveLock(&DeviceExtension->RemoveLock, 'dmaR', 1, 0);
2361         InitializeListHead(&DeviceExtension->DiskList);
2362         DeviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
2363         DeviceExtension->DeviceObject = DeviceObject;
2364 
2365         /* Register the RAM disk device interface */
2366         Status = IoRegisterDeviceInterface(PhysicalDeviceObject,
2367                                            &RamdiskBusInterface,
2368                                            NULL,
2369                                            &DeviceExtension->BusDeviceName);
2370         if (!NT_SUCCESS(Status))
2371         {
2372             /* Fail */
2373             IoDeleteDevice(DeviceObject);
2374             return Status;
2375         }
2376 
2377         /* Attach us to the device stack */
2378         AttachedDevice = IoAttachDeviceToDeviceStack(DeviceObject,
2379                                                      PhysicalDeviceObject);
2380         DeviceExtension->AttachedDevice = AttachedDevice;
2381         if (!AttachedDevice)
2382         {
2383             /* Fail */
2384             IoSetDeviceInterfaceState(&DeviceExtension->BusDeviceName, 0);
2385             RtlFreeUnicodeString(&DeviceExtension->BusDeviceName);
2386             IoDeleteDevice(DeviceObject);
2387             return STATUS_NO_SUCH_DEVICE;
2388         }
2389 
2390         /* Bus FDO is initialized */
2391         RamdiskBusFdo = DeviceObject;
2392 
2393         /* Loop for loader block */
2394         if (KeLoaderBlock)
2395         {
2396             /* Are we being booted from setup? Not yet supported */
2397             if (KeLoaderBlock->SetupLdrBlock)
2398                 DPRINT1("FIXME: RamdiskAddDevice is UNSUPPORTED when being started from SETUPLDR!\n");
2399             // ASSERT(!KeLoaderBlock->SetupLdrBlock);
2400         }
2401 
2402         /* All done */
2403         DeviceObject->Flags &= DO_DEVICE_INITIALIZING;
2404         Status = STATUS_SUCCESS;
2405     }
2406 
2407     /* Return status */
2408     return Status;
2409 }
2410 
2411 NTSTATUS
2412 NTAPI
2413 DriverEntry(IN PDRIVER_OBJECT DriverObject,
2414             IN PUNICODE_STRING RegistryPath)
2415 {
2416     PCHAR BootDeviceName, CommandLine;
2417     PDEVICE_OBJECT PhysicalDeviceObject = NULL;
2418     NTSTATUS Status;
2419     DPRINT("RAM Disk Driver Initialized\n");
2420 
2421     /* Query ramdisk parameters */
2422     QueryParameters(RegistryPath);
2423 
2424     /* Save the registry path */
2425     DriverRegistryPath = *RegistryPath;
2426     DriverRegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool,
2427                                                       RegistryPath->Length +
2428                                                       sizeof(UNICODE_NULL),
2429                                                       'dmaR');
2430     if (!DriverRegistryPath.Buffer) return STATUS_INSUFFICIENT_RESOURCES;
2431     RtlCopyUnicodeString(&DriverRegistryPath, RegistryPath);
2432 
2433     /* Set device routines */
2434     DriverObject->MajorFunction[IRP_MJ_CREATE] = RamdiskOpenClose;
2435     DriverObject->MajorFunction[IRP_MJ_CLOSE] = RamdiskOpenClose;
2436     DriverObject->MajorFunction[IRP_MJ_READ] = RamdiskReadWrite;
2437     DriverObject->MajorFunction[IRP_MJ_WRITE] = RamdiskReadWrite;
2438     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = RamdiskDeviceControl;
2439     DriverObject->MajorFunction[IRP_MJ_PNP] = RamdiskPnp;
2440     DriverObject->MajorFunction[IRP_MJ_POWER] = RamdiskPower;
2441     DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = RamdiskSystemControl;
2442     DriverObject->MajorFunction[IRP_MJ_SCSI] = RamdiskScsi;
2443     DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = RamdiskFlushBuffers;
2444     DriverObject->DriverExtension->AddDevice = RamdiskAddDevice;
2445     DriverObject->DriverUnload = RamdiskUnload;
2446 
2447     /* Check for a loader block */
2448     if (KeLoaderBlock)
2449     {
2450         /* Get the boot device name */
2451         BootDeviceName = KeLoaderBlock->ArcBootDeviceName;
2452         if (BootDeviceName)
2453         {
2454             /* Check if we're booting from ramdisk */
2455             if ((strlen(BootDeviceName) >= 10) &&
2456                 !(_strnicmp(BootDeviceName, "ramdisk(0)", 10)))
2457             {
2458                 /* We'll have to tell the PnP Manager */
2459                 ReportDetectedDevice = TRUE;
2460 
2461                 /* Check for a command line */
2462                 CommandLine = KeLoaderBlock->LoadOptions;
2463                 if (CommandLine)
2464                 {
2465                     /* Check if this is an ISO boot */
2466                     if (strstr(CommandLine, "RDEXPORTASCD"))
2467                     {
2468                         /* Remember for later */
2469                         ExportBootDiskAsCd = TRUE;
2470                     }
2471 
2472                     /* Check if this is PE boot */
2473                     if (strstr(CommandLine, "MININT"))
2474                     {
2475                         /* Remember for later */
2476                         IsWinPEBoot = TRUE;
2477                     }
2478                 }
2479             }
2480 
2481         }
2482     }
2483 
2484     /* Installing from Ramdisk isn't supported yet */
2485     if (KeLoaderBlock->SetupLdrBlock)
2486         DPRINT1("FIXME: Installing from RamDisk is UNSUPPORTED!\n");
2487     // ASSERT(!KeLoaderBlock->SetupLdrBlock);
2488 
2489     /* Are we reporting the device */
2490     if (ReportDetectedDevice)
2491     {
2492         /* Do it */
2493         Status = IoReportDetectedDevice(DriverObject,
2494                                         InterfaceTypeUndefined,
2495                                         0xFFFFFFFF,
2496                                         0xFFFFFFFF,
2497                                         NULL,
2498                                         NULL,
2499                                         0,
2500                                         &PhysicalDeviceObject);
2501         if (NT_SUCCESS(Status))
2502         {
2503             /* Create the device object */
2504             Status = RamdiskAddDevice(DriverObject, PhysicalDeviceObject);
2505             if (NT_SUCCESS(Status))
2506             {
2507                 /* We are done */
2508                 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
2509                 Status = STATUS_SUCCESS;
2510             }
2511         }
2512     }
2513     else
2514     {
2515         /* Done */
2516         Status = STATUS_SUCCESS;
2517     }
2518 
2519     /* Done */
2520     return Status;
2521 }
2522