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