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