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         case BusQueryContainerID:
1737         {
1738             /* Nothing to do */
1739             break;
1740         }
1741     }
1742 
1743     Irp->IoStatus.Status = Status;
1744     Irp->IoStatus.Information = (ULONG_PTR)OutputString;
1745     IoCompleteRequest(Irp, IO_NO_INCREMENT);
1746     return Status;
1747 }
1748 
1749 NTSTATUS
1750 NTAPI
1751 RamdiskQueryCapabilities(IN PDEVICE_OBJECT DeviceObject,
1752                          IN PIRP Irp)
1753 {
1754     NTSTATUS Status;
1755     PIO_STACK_LOCATION IoStackLocation;
1756     PDEVICE_CAPABILITIES DeviceCapabilities;
1757     PRAMDISK_DRIVE_EXTENSION DriveExtension;
1758 
1759     IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
1760     DeviceCapabilities = IoStackLocation->Parameters.DeviceCapabilities.Capabilities;
1761     DriveExtension = DeviceObject->DeviceExtension;
1762 
1763     /* Validate our input buffer */
1764     if (DeviceCapabilities->Version != 1 ||
1765         DeviceCapabilities->Size < sizeof(DEVICE_CAPABILITIES))
1766     {
1767         Status = STATUS_UNSUCCESSFUL;
1768     }
1769     else
1770     {
1771         /* And set everything we know about our capabilities */
1772         DeviceCapabilities->Removable = MarkRamdisksAsRemovable;
1773         DeviceCapabilities->UniqueID = TRUE;
1774         DeviceCapabilities->SilentInstall = TRUE;
1775         DeviceCapabilities->RawDeviceOK = TRUE;
1776         DeviceCapabilities->SurpriseRemovalOK = (DriveExtension->DiskType != RAMDISK_REGISTRY_DISK);
1777         DeviceCapabilities->NoDisplayInUI = TRUE;
1778         Status = STATUS_SUCCESS;
1779     }
1780 
1781     Irp->IoStatus.Status = Status;
1782     IoCompleteRequest(Irp, IO_NO_INCREMENT);
1783     return Status;
1784 }
1785 
1786 NTSTATUS
1787 NTAPI
1788 RamdiskQueryDeviceText(IN PRAMDISK_DRIVE_EXTENSION DriveExtension,
1789                        IN PIRP Irp)
1790 {
1791     NTSTATUS Status;
1792     PIO_STACK_LOCATION IoStackLocation;
1793     DEVICE_TEXT_TYPE DeviceTextType;
1794     PWSTR OutputString = NULL;
1795 
1796     IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
1797     DeviceTextType = IoStackLocation->Parameters.QueryDeviceText.DeviceTextType;
1798     Status = STATUS_SUCCESS;
1799 
1800     /* Just copy our constants, according to the input */
1801     switch (DeviceTextType)
1802     {
1803         case DeviceTextDescription:
1804         {
1805             OutputString = ExAllocatePoolWithTag(PagedPool, sizeof(L"RamDisk"), 'dmaR');
1806             if (OutputString == NULL)
1807             {
1808                 Status = STATUS_INSUFFICIENT_RESOURCES;
1809                 break;
1810             }
1811 
1812             wcsncpy(OutputString, L"RamDisk", sizeof(L"RamDisk") / sizeof(WCHAR));
1813 
1814             break;
1815         }
1816 
1817         case DeviceTextLocationInformation:
1818         {
1819             OutputString = ExAllocatePoolWithTag(PagedPool, sizeof(L"RamDisk\\0"), 'dmaR');
1820             if (OutputString == NULL)
1821             {
1822                 Status = STATUS_INSUFFICIENT_RESOURCES;
1823                 break;
1824             }
1825 
1826             wcsncpy(OutputString, L"RamDisk\\0", sizeof(L"RamDisk\\0") / sizeof(WCHAR));
1827 
1828             break;
1829         }
1830     }
1831 
1832     Irp->IoStatus.Status = Status;
1833     Irp->IoStatus.Information = (ULONG_PTR)OutputString;
1834     IoCompleteRequest(Irp, IO_NO_INCREMENT);
1835     return Status;
1836 }
1837 
1838 NTSTATUS
1839 NTAPI
1840 RamdiskQueryBusInformation(IN PDEVICE_OBJECT DeviceObject,
1841                            IN PIRP Irp)
1842 {
1843     PPNP_BUS_INFORMATION PnpBusInfo;
1844     NTSTATUS Status = STATUS_SUCCESS;
1845 
1846     /* Allocate output memory */
1847     PnpBusInfo = ExAllocatePoolWithTag(PagedPool, sizeof(*PnpBusInfo), 'dmaR');
1848     if (PnpBusInfo == NULL)
1849     {
1850         Status = STATUS_INSUFFICIENT_RESOURCES;
1851     }
1852     else
1853     {
1854         /* Copy our bus GUID and set our legacy type */
1855         RtlCopyMemory(&PnpBusInfo->BusTypeGuid, &GUID_BUS_TYPE_RAMDISK, sizeof(GUID));
1856         PnpBusInfo->LegacyBusType = PNPBus;
1857         PnpBusInfo->BusNumber = 0;
1858     }
1859 
1860     Irp->IoStatus.Status = Status;
1861     Irp->IoStatus.Information = (ULONG_PTR)PnpBusInfo;
1862     IoCompleteRequest(Irp, IO_NO_INCREMENT);
1863     return Status;
1864 }
1865 
1866 NTSTATUS
1867 NTAPI
1868 RamdiskIoCompletionRoutine(IN PDEVICE_OBJECT DeviceObject,
1869                            IN PIRP Irp,
1870                            IN PVOID Context)
1871 
1872 {
1873     /* Just set the event to unlock caller */
1874     KeSetEvent((PKEVENT)Context, 0, FALSE);
1875 
1876     return STATUS_MORE_PROCESSING_REQUIRED;
1877 }
1878 
1879 NTSTATUS
1880 NTAPI
1881 RamdiskPnp(IN PDEVICE_OBJECT DeviceObject,
1882            IN PIRP Irp)
1883 {
1884     PIO_STACK_LOCATION IoStackLocation;
1885     PRAMDISK_BUS_EXTENSION DeviceExtension;
1886     NTSTATUS Status;
1887     UCHAR Minor;
1888     KEVENT Event;
1889 
1890     /* Get the device extension and stack location */
1891     DeviceExtension = DeviceObject->DeviceExtension;
1892     IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
1893     Minor = IoStackLocation->MinorFunction;
1894 
1895     /* Check if the bus is removed */
1896     if (DeviceExtension->State == RamdiskStateBusRemoved)
1897     {
1898         /* Only remove-device and query-id are allowed */
1899         if ((Minor != IRP_MN_REMOVE_DEVICE) && (Minor != IRP_MN_QUERY_ID))
1900         {
1901             /* Fail anything else */
1902             Status = STATUS_NO_SUCH_DEVICE;
1903             Irp->IoStatus.Status = Status;
1904             IoCompleteRequest(Irp, IO_NO_INCREMENT);
1905             return Status;
1906         }
1907     }
1908 
1909     /* Acquire the remove lock */
1910     Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Irp);
1911     if (!NT_SUCCESS(Status))
1912     {
1913         /* Fail the IRP */
1914         Irp->IoStatus.Information = 0;
1915         Irp->IoStatus.Status = Status;
1916         IoCompleteRequest(Irp, IO_NO_INCREMENT);
1917         return Status;
1918     }
1919 
1920     /* Query the IRP type */
1921     switch (Minor)
1922     {
1923         case IRP_MN_START_DEVICE:
1924         {
1925             if (DeviceExtension->Type == RamdiskDrive)
1926             {
1927                 ULONG ResultLength;
1928                 DEVICE_INSTALL_STATE InstallState;
1929                 PRAMDISK_DRIVE_EXTENSION DriveExtension = (PRAMDISK_DRIVE_EXTENSION)DeviceExtension;
1930 
1931                 /* If we already have a drive name, free it */
1932                 if (DriveExtension->DriveDeviceName.Buffer)
1933                 {
1934                     ExFreePool(DriveExtension->DriveDeviceName.Buffer);
1935                 }
1936 
1937                 /* Register our device interface */
1938                 if (DriveExtension->DiskType != RAMDISK_REGISTRY_DISK)
1939                 {
1940                     Status = IoRegisterDeviceInterface(DeviceObject,
1941                                                        &GUID_DEVINTERFACE_VOLUME,
1942                                                        NULL,
1943                                                        &DriveExtension->DriveDeviceName);
1944                 }
1945                 else
1946                 {
1947                     Status = IoRegisterDeviceInterface(DeviceObject,
1948                                                        &RamdiskDiskInterface,
1949                                                        NULL,
1950                                                        &DriveExtension->DriveDeviceName);
1951                 }
1952 
1953                 /* If we were asked not to assign a drive letter or if getting
1954                  * a name failed, just return saying we're now started */
1955                 if (DriveExtension->DiskOptions.NoDriveLetter ||
1956                     DriveExtension->DriveDeviceName.Buffer == NULL)
1957                 {
1958                     DriveExtension->State = RamdiskStateStarted;
1959                     Irp->IoStatus.Status = Status;
1960                     break;
1961                 }
1962 
1963                 /* Now get our installation state */
1964                 Status = IoGetDeviceProperty(DeviceObject,
1965                                              DevicePropertyInstallState,
1966                                              sizeof(InstallState),
1967                                              &InstallState,
1968                                              &ResultLength);
1969                 /* If querying the information failed, assume success */
1970                 if (!NT_SUCCESS(Status))
1971                 {
1972                     InstallState = InstallStateInstalled;
1973                 }
1974 
1975                 /* If we were properly installed, then, enable the interface */
1976                 if (InstallState == InstallStateInstalled)
1977                 {
1978                     Status = IoSetDeviceInterfaceState(&DriveExtension->DriveDeviceName, TRUE);
1979                 }
1980 
1981                 /* We're fine & up */
1982                 DriveExtension->State = RamdiskStateStarted;
1983                 Irp->IoStatus.Status = Status;
1984                 break;
1985             }
1986 
1987             /* Prepare next stack to pass it down */
1988             IoCopyCurrentIrpStackLocationToNext(Irp);
1989 
1990             /* Initialize our notification event & our completion routine */
1991             KeInitializeEvent(&Event, NotificationEvent, FALSE);
1992             IoSetCompletionRoutine(Irp, RamdiskIoCompletionRoutine, &Event, TRUE, TRUE, TRUE);
1993 
1994             /* Call lower driver */
1995             Status = IoCallDriver(DeviceExtension->AttachedDevice, Irp);
1996             if (Status == STATUS_PENDING)
1997             {
1998                 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1999                 Status = Irp->IoStatus.Status;
2000             }
2001 
2002             /* If it succeed to start then enable ourselves and we're up! */
2003             if (NT_SUCCESS(Status))
2004             {
2005                 Status = IoSetDeviceInterfaceState(&DeviceExtension->DriveDeviceName, TRUE);
2006                 DeviceExtension->State = RamdiskStateStarted;
2007             }
2008 
2009             Irp->IoStatus.Status = Status;
2010             break;
2011         }
2012 
2013         case IRP_MN_QUERY_STOP_DEVICE:
2014         case IRP_MN_CANCEL_STOP_DEVICE:
2015         case IRP_MN_STOP_DEVICE:
2016         case IRP_MN_QUERY_REMOVE_DEVICE:
2017         case IRP_MN_CANCEL_REMOVE_DEVICE:
2018         {
2019             UNIMPLEMENTED_DBGBREAK("PnP IRP: %lx\n", Minor);
2020             break;
2021         }
2022 
2023         case IRP_MN_REMOVE_DEVICE:
2024         {
2025             /* Remove the proper device */
2026             if (DeviceExtension->Type == RamdiskBus)
2027             {
2028                 Status = RamdiskRemoveBusDevice(DeviceObject, Irp);
2029 
2030                 /* Return here, lower device has already been called
2031                  * And remove lock released. This is needed by the function. */
2032                 return Status;
2033             }
2034             else
2035             {
2036                 Status = RamdiskDeleteDiskDevice(DeviceObject, Irp);
2037 
2038                 /* Complete the IRP here and return
2039                  * Here again we don't have to release remove lock
2040                  * This has already been done by the function. */
2041                 Irp->IoStatus.Status = Status;
2042                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2043                 return Status;
2044             }
2045         }
2046 
2047         case IRP_MN_SURPRISE_REMOVAL:
2048             UNIMPLEMENTED_DBGBREAK("PnP IRP: %lx\n", Minor);
2049             break;
2050 
2051         case IRP_MN_QUERY_ID:
2052         {
2053             /* Are we a drive? */
2054             if (DeviceExtension->Type == RamdiskDrive)
2055             {
2056                 Status = RamdiskQueryId((PRAMDISK_DRIVE_EXTENSION)DeviceExtension, Irp);
2057             }
2058             break;
2059         }
2060 
2061         case IRP_MN_QUERY_BUS_INFORMATION:
2062         {
2063             /* Are we a drive? */
2064             if (DeviceExtension->Type == RamdiskDrive)
2065             {
2066                 Status = RamdiskQueryBusInformation(DeviceObject, Irp);
2067             }
2068             break;
2069         }
2070 
2071         case IRP_MN_EJECT:
2072             UNIMPLEMENTED_DBGBREAK("PnP IRP: %lx\n", Minor);
2073             break;
2074 
2075         case IRP_MN_QUERY_DEVICE_TEXT:
2076         {
2077             /* Are we a drive? */
2078             if (DeviceExtension->Type == RamdiskDrive)
2079             {
2080                 Status = RamdiskQueryDeviceText((PRAMDISK_DRIVE_EXTENSION)DeviceExtension, Irp);
2081             }
2082             break;
2083         }
2084 
2085         case IRP_MN_QUERY_DEVICE_RELATIONS:
2086         {
2087             /* Call our main routine */
2088             Status = RamdiskQueryDeviceRelations(IoStackLocation->
2089                                                  Parameters.
2090                                                  QueryDeviceRelations.Type,
2091                                                  DeviceObject,
2092                                                  Irp);
2093             goto ReleaseAndReturn;
2094         }
2095 
2096         case IRP_MN_QUERY_CAPABILITIES:
2097         {
2098             /* Are we a drive? */
2099             if (DeviceExtension->Type == RamdiskDrive)
2100             {
2101                 Status = RamdiskQueryCapabilities(DeviceObject, Irp);
2102             }
2103             break;
2104         }
2105 
2106         case IRP_MN_QUERY_RESOURCES:
2107         case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
2108         {
2109             /* Complete immediately without touching it */
2110             IoCompleteRequest(Irp, IO_NO_INCREMENT);
2111             goto ReleaseAndReturn;
2112         }
2113 
2114         default:
2115             DPRINT1("Illegal IRP: %lx\n", Minor);
2116             break;
2117     }
2118 
2119     /* Are we the bus? */
2120     if (DeviceExtension->Type == RamdiskBus)
2121     {
2122         /* Do we have an attached device? */
2123         if (DeviceExtension->AttachedDevice)
2124         {
2125             /* Forward the IRP */
2126             IoSkipCurrentIrpStackLocation(Irp);
2127             Status = IoCallDriver(DeviceExtension->AttachedDevice, Irp);
2128         }
2129     }
2130 
2131     /* Release the lock and return status */
2132 ReleaseAndReturn:
2133     IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp);
2134     return Status;
2135 }
2136 
2137 NTSTATUS
2138 NTAPI
2139 RamdiskPower(IN PDEVICE_OBJECT DeviceObject,
2140              IN PIRP Irp)
2141 {
2142     NTSTATUS Status;
2143     PIO_STACK_LOCATION IoStackLocation;
2144     PRAMDISK_BUS_EXTENSION DeviceExtension;
2145 
2146     DeviceExtension = DeviceObject->DeviceExtension;
2147 
2148     /* If we have a device extension, take extra caution with the lower driver */
2149     if (DeviceExtension != NULL)
2150     {
2151         PoStartNextPowerIrp(Irp);
2152 
2153         /* Device has not been removed yet, so pass to the attached/lower driver */
2154         if (DeviceExtension->State < RamdiskStateBusRemoved)
2155         {
2156             IoSkipCurrentIrpStackLocation(Irp);
2157             return PoCallDriver(DeviceExtension->AttachedDevice, Irp);
2158         }
2159         /* Otherwise, simply complete the IRP notifying that deletion is pending */
2160         else
2161         {
2162             Irp->IoStatus.Status = STATUS_DELETE_PENDING;
2163             IoCompleteRequest(Irp, IO_NO_INCREMENT);
2164             return STATUS_DELETE_PENDING;
2165         }
2166     }
2167 
2168     /* Get stack and deal with minor functions */
2169     IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
2170     switch (IoStackLocation->MinorFunction)
2171     {
2172         case IRP_MN_SET_POWER:
2173         {
2174             /* If setting device power state it's all fine and return success */
2175             if (DevicePowerState)
2176             {
2177                 Irp->IoStatus.Status = STATUS_SUCCESS;
2178             }
2179 
2180             /* Get appropriate status for return */
2181             Status = Irp->IoStatus.Status;
2182             PoStartNextPowerIrp(Irp);
2183             IoCompleteRequest(Irp, IO_NO_INCREMENT);
2184             break;
2185         }
2186 
2187         case IRP_MN_QUERY_POWER:
2188         {
2189             /* We can obviously accept all states so just return success */
2190             Status = Irp->IoStatus.Status = STATUS_SUCCESS;
2191             PoStartNextPowerIrp(Irp);
2192             IoCompleteRequest(Irp, IO_NO_INCREMENT);
2193             break;
2194         }
2195 
2196         default:
2197         {
2198             /* Just complete and save status for return */
2199             Status = Irp->IoStatus.Status;
2200             PoStartNextPowerIrp(Irp);
2201             IoCompleteRequest(Irp, IO_NO_INCREMENT);
2202             break;
2203         }
2204     }
2205 
2206     return Status;
2207 }
2208 
2209 NTSTATUS
2210 NTAPI
2211 RamdiskSystemControl(IN PDEVICE_OBJECT DeviceObject,
2212                      IN PIRP Irp)
2213 {
2214     NTSTATUS Status;
2215     PRAMDISK_BUS_EXTENSION DeviceExtension;
2216 
2217     DeviceExtension = DeviceObject->DeviceExtension;
2218 
2219     /* If we have a device extension, forward the IRP to the attached device */
2220     if (DeviceExtension != NULL)
2221     {
2222         IoSkipCurrentIrpStackLocation(Irp);
2223         Status = IoCallDriver(DeviceExtension->AttachedDevice, Irp);
2224     }
2225     /* Otherwise just complete the request
2226      * And return the status with which we complete it */
2227     else
2228     {
2229         Status = Irp->IoStatus.Status;
2230         IoCompleteRequest(Irp, IO_NO_INCREMENT);
2231     }
2232 
2233     return Status;
2234 }
2235 
2236 NTSTATUS
2237 NTAPI
2238 RamdiskScsi(IN PDEVICE_OBJECT DeviceObject,
2239             IN PIRP Irp)
2240 {
2241     NTSTATUS Status;
2242     PRAMDISK_BUS_EXTENSION DeviceExtension;
2243 
2244     DeviceExtension = DeviceObject->DeviceExtension;
2245 
2246     /* Having a proper device is mandatory */
2247     if (DeviceExtension->State > RamdiskStateStopped)
2248     {
2249         Status = STATUS_DEVICE_DOES_NOT_EXIST;
2250         goto CompleteIRP;
2251     }
2252 
2253     /* Acquire the remove lock */
2254     Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Irp);
2255     if (!NT_SUCCESS(Status))
2256     {
2257         goto CompleteIRP;
2258     }
2259 
2260     /* Queue the IRP for worker */
2261     Status = SendIrpToThread(DeviceObject, Irp);
2262     if (Status != STATUS_PENDING)
2263     {
2264         goto CompleteIRP;
2265     }
2266 
2267     /* Release the remove lock */
2268     IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp);
2269     goto Quit;
2270 
2271 CompleteIRP:
2272     Irp->IoStatus.Information = 0;
2273     Irp->IoStatus.Status = Status;
2274     IoCompleteRequest(Irp, IO_NO_INCREMENT);
2275 
2276 Quit:
2277     return Status;
2278 }
2279 
2280 NTSTATUS
2281 NTAPI
2282 RamdiskFlushBuffers(IN PDEVICE_OBJECT DeviceObject,
2283                     IN PIRP Irp)
2284 {
2285     NTSTATUS Status;
2286     PRAMDISK_DRIVE_EXTENSION DeviceExtension;
2287 
2288     DeviceExtension = DeviceObject->DeviceExtension;
2289 
2290     /* Ensure we have drive extension
2291      * Only perform flush on disks that have been created
2292      * from registry entries */
2293     if (DeviceExtension->Type != RamdiskDrive ||
2294         DeviceExtension->DiskType > RAMDISK_MEMORY_MAPPED_DISK)
2295     {
2296         Irp->IoStatus.Information = 0;
2297         Irp->IoStatus.Status = STATUS_SUCCESS;
2298         IoCompleteRequest(Irp, IO_NO_INCREMENT);
2299         return STATUS_SUCCESS;
2300     }
2301 
2302     /* Queue the IRP for worker */
2303     Status = SendIrpToThread(DeviceObject, Irp);
2304     if (Status != STATUS_PENDING)
2305     {
2306         /* Queuing failed - complete the IRP and return failure */
2307         Irp->IoStatus.Information = 0;
2308         Irp->IoStatus.Status = Status;
2309         IoCompleteRequest(Irp, IO_NO_INCREMENT);
2310     }
2311 
2312     return Status;
2313 }
2314 
2315 VOID
2316 NTAPI
2317 RamdiskUnload(IN PDRIVER_OBJECT DriverObject)
2318 {
2319     /* Just release registry path if previously allocated */
2320     if (DriverRegistryPath.Buffer)
2321     {
2322         ExFreePoolWithTag(DriverRegistryPath.Buffer, 'dmaR');
2323     }
2324 }
2325 
2326 NTSTATUS
2327 NTAPI
2328 RamdiskAddDevice(IN PDRIVER_OBJECT DriverObject,
2329                  IN PDEVICE_OBJECT PhysicalDeviceObject)
2330 {
2331     PRAMDISK_BUS_EXTENSION DeviceExtension;
2332     PDEVICE_OBJECT AttachedDevice;
2333     NTSTATUS Status;
2334     UNICODE_STRING DeviceName;
2335     PDEVICE_OBJECT DeviceObject;
2336 
2337     /* Only create the bus FDO once */
2338     if (RamdiskBusFdo) return STATUS_DEVICE_ALREADY_ATTACHED;
2339 
2340     /* Create the bus FDO */
2341     RtlInitUnicodeString(&DeviceName, L"\\Device\\Ramdisk");
2342     Status = IoCreateDevice(DriverObject,
2343                             sizeof(RAMDISK_BUS_EXTENSION),
2344                             &DeviceName,
2345                             FILE_DEVICE_BUS_EXTENDER,
2346                             FILE_DEVICE_SECURE_OPEN,
2347                             0,
2348                             &DeviceObject);
2349     if (NT_SUCCESS(Status))
2350     {
2351         /* Initialize the bus FDO extension */
2352         DeviceExtension = DeviceObject->DeviceExtension;
2353         RtlZeroMemory(DeviceExtension, sizeof(*DeviceExtension));
2354 
2355         /* Set bus FDO flags */
2356         DeviceObject->Flags |= DO_POWER_PAGABLE | DO_DIRECT_IO;
2357 
2358         /* Setup the bus FDO extension */
2359         DeviceExtension->Type = RamdiskBus;
2360         ExInitializeFastMutex(&DeviceExtension->DiskListLock);
2361         IoInitializeRemoveLock(&DeviceExtension->RemoveLock, 'dmaR', 1, 0);
2362         InitializeListHead(&DeviceExtension->DiskList);
2363         DeviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
2364         DeviceExtension->DeviceObject = DeviceObject;
2365 
2366         /* Register the RAM disk device interface */
2367         Status = IoRegisterDeviceInterface(PhysicalDeviceObject,
2368                                            &RamdiskBusInterface,
2369                                            NULL,
2370                                            &DeviceExtension->BusDeviceName);
2371         if (!NT_SUCCESS(Status))
2372         {
2373             /* Fail */
2374             IoDeleteDevice(DeviceObject);
2375             return Status;
2376         }
2377 
2378         /* Attach us to the device stack */
2379         AttachedDevice = IoAttachDeviceToDeviceStack(DeviceObject,
2380                                                      PhysicalDeviceObject);
2381         DeviceExtension->AttachedDevice = AttachedDevice;
2382         if (!AttachedDevice)
2383         {
2384             /* Fail */
2385             IoSetDeviceInterfaceState(&DeviceExtension->BusDeviceName, 0);
2386             RtlFreeUnicodeString(&DeviceExtension->BusDeviceName);
2387             IoDeleteDevice(DeviceObject);
2388             return STATUS_NO_SUCH_DEVICE;
2389         }
2390 
2391         /* Bus FDO is initialized */
2392         RamdiskBusFdo = DeviceObject;
2393 
2394         /* Loop for loader block */
2395         if (KeLoaderBlock)
2396         {
2397             /* Are we being booted from setup? Not yet supported */
2398             if (KeLoaderBlock->SetupLdrBlock)
2399                 DPRINT1("FIXME: RamdiskAddDevice is UNSUPPORTED when being started from SETUPLDR!\n");
2400             // ASSERT(!KeLoaderBlock->SetupLdrBlock);
2401         }
2402 
2403         /* All done */
2404         DeviceObject->Flags &= DO_DEVICE_INITIALIZING;
2405         Status = STATUS_SUCCESS;
2406     }
2407 
2408     /* Return status */
2409     return Status;
2410 }
2411 
2412 NTSTATUS
2413 NTAPI
2414 DriverEntry(IN PDRIVER_OBJECT DriverObject,
2415             IN PUNICODE_STRING RegistryPath)
2416 {
2417     PCHAR BootDeviceName, CommandLine;
2418     PDEVICE_OBJECT PhysicalDeviceObject = NULL;
2419     NTSTATUS Status;
2420     DPRINT("RAM Disk Driver Initialized\n");
2421 
2422     /* Save the registry path */
2423     DriverRegistryPath.MaximumLength = RegistryPath->Length + sizeof(UNICODE_NULL);
2424     DriverRegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool,
2425                                                       DriverRegistryPath.MaximumLength,
2426                                                       'dmaR');
2427     if (!DriverRegistryPath.Buffer)
2428     {
2429         return STATUS_INSUFFICIENT_RESOURCES;
2430     }
2431     RtlCopyUnicodeString(&DriverRegistryPath, RegistryPath);
2432 
2433     /* Query ramdisk parameters */
2434     QueryParameters(&DriverRegistryPath);
2435 
2436     /* Set device routines */
2437     DriverObject->MajorFunction[IRP_MJ_CREATE] = RamdiskOpenClose;
2438     DriverObject->MajorFunction[IRP_MJ_CLOSE] = RamdiskOpenClose;
2439     DriverObject->MajorFunction[IRP_MJ_READ] = RamdiskReadWrite;
2440     DriverObject->MajorFunction[IRP_MJ_WRITE] = RamdiskReadWrite;
2441     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = RamdiskDeviceControl;
2442     DriverObject->MajorFunction[IRP_MJ_PNP] = RamdiskPnp;
2443     DriverObject->MajorFunction[IRP_MJ_POWER] = RamdiskPower;
2444     DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = RamdiskSystemControl;
2445     DriverObject->MajorFunction[IRP_MJ_SCSI] = RamdiskScsi;
2446     DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = RamdiskFlushBuffers;
2447     DriverObject->DriverExtension->AddDevice = RamdiskAddDevice;
2448     DriverObject->DriverUnload = RamdiskUnload;
2449 
2450     /* Check for a loader block */
2451     if (KeLoaderBlock)
2452     {
2453         /* Get the boot device name */
2454         BootDeviceName = KeLoaderBlock->ArcBootDeviceName;
2455         if (BootDeviceName)
2456         {
2457             /* Check if we're booting from ramdisk */
2458             if ((strlen(BootDeviceName) >= 10) &&
2459                 !(_strnicmp(BootDeviceName, "ramdisk(0)", 10)))
2460             {
2461                 /* We'll have to tell the PnP Manager */
2462                 ReportDetectedDevice = TRUE;
2463 
2464                 /* Check for a command line */
2465                 CommandLine = KeLoaderBlock->LoadOptions;
2466                 if (CommandLine)
2467                 {
2468                     /* Check if this is an ISO boot */
2469                     if (strstr(CommandLine, "RDEXPORTASCD"))
2470                     {
2471                         /* Remember for later */
2472                         ExportBootDiskAsCd = TRUE;
2473                     }
2474 
2475                     /* Check if this is PE boot */
2476                     if (strstr(CommandLine, "MININT"))
2477                     {
2478                         /* Remember for later */
2479                         IsWinPEBoot = TRUE;
2480                     }
2481                 }
2482             }
2483 
2484         }
2485     }
2486 
2487     /* Installing from Ramdisk isn't supported yet */
2488     if (KeLoaderBlock->SetupLdrBlock)
2489         DPRINT1("FIXME: Installing from RamDisk is UNSUPPORTED!\n");
2490     // ASSERT(!KeLoaderBlock->SetupLdrBlock);
2491 
2492     /* Are we reporting the device */
2493     if (ReportDetectedDevice)
2494     {
2495         /* Do it */
2496         Status = IoReportDetectedDevice(DriverObject,
2497                                         InterfaceTypeUndefined,
2498                                         0xFFFFFFFF,
2499                                         0xFFFFFFFF,
2500                                         NULL,
2501                                         NULL,
2502                                         0,
2503                                         &PhysicalDeviceObject);
2504         if (NT_SUCCESS(Status))
2505         {
2506             /* Create the device object */
2507             Status = RamdiskAddDevice(DriverObject, PhysicalDeviceObject);
2508             if (NT_SUCCESS(Status))
2509             {
2510                 /* We are done */
2511                 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
2512                 Status = STATUS_SUCCESS;
2513             }
2514         }
2515     }
2516     else
2517     {
2518         /* Done */
2519         Status = STATUS_SUCCESS;
2520     }
2521 
2522     /* Done */
2523     return Status;
2524 }
2525