[SAL]
[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 0,
627 1);
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;
776 ASSERT(FALSE); // while (TRUE);
777 return STATUS_SUCCESS;
778 }
779
780 NTSTATUS
781 NTAPI
782 RamdiskCreateRamdisk(IN PDEVICE_OBJECT DeviceObject,
783 IN PIRP Irp,
784 IN BOOLEAN ValidateOnly)
785 {
786 PRAMDISK_CREATE_INPUT Input;
787 ULONG Length;
788 PRAMDISK_BUS_EXTENSION DeviceExtension;
789 PRAMDISK_DRIVE_EXTENSION DriveExtension;
790 ULONG DiskType;
791 PWCHAR FileNameStart, FileNameEnd;
792 NTSTATUS Status;
793 PIO_STACK_LOCATION IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
794
795 //
796 // Get the device extension and our input data
797 //
798 DeviceExtension = DeviceObject->DeviceExtension;
799 Length = IoStackLocation->Parameters.DeviceIoControl.InputBufferLength;
800 Input = (PRAMDISK_CREATE_INPUT)Irp->AssociatedIrp.SystemBuffer;
801
802 //
803 // Validate input parameters
804 //
805 if ((Length < sizeof(RAMDISK_CREATE_INPUT)) ||
806 (Input->Version != sizeof(RAMDISK_CREATE_INPUT)))
807 {
808 //
809 // Invalid input
810 //
811 return STATUS_INVALID_PARAMETER;
812 }
813
814 //
815 // Validate the disk type
816 //
817 DiskType = Input->DiskType;
818 if (DiskType == RAMDISK_WIM_DISK) return STATUS_INVALID_PARAMETER;
819
820 //
821 // Look at the disk type
822 //
823 if (DiskType == RAMDISK_BOOT_DISK)
824 {
825 //
826 // We only allow this as an early-init boot
827 //
828 if (!KeLoaderBlock) return STATUS_INVALID_PARAMETER;
829
830 //
831 // Save command-line flags
832 //
833 if (ExportBootDiskAsCd) Input->Options.ExportAsCd = TRUE;
834 if (IsWinPEBoot) Input->Options.NoDriveLetter = TRUE;
835 }
836
837 //
838 // Validate the disk type
839 //
840 if ((Input->Options.ExportAsCd) && (DiskType != RAMDISK_BOOT_DISK))
841 {
842 //
843 // If the type isn't CDFS, it has to at least be raw CD
844 //
845 if (DiskType != RAMDISK_MEMORY_MAPPED_DISK) return STATUS_INVALID_PARAMETER;
846 }
847
848 //
849 // Check if this is an actual file
850 //
851 if (DiskType <= RAMDISK_MEMORY_MAPPED_DISK)
852 {
853 //
854 // Validate the file name
855 //
856 FileNameStart = (PWCHAR)((ULONG_PTR)Input + Length);
857 FileNameEnd = Input->FileName + 1;
858 while ((FileNameEnd < FileNameStart) && *(FileNameEnd)) FileNameEnd++;
859 if (FileNameEnd == FileNameStart) return STATUS_INVALID_PARAMETER;
860 }
861
862 //
863 // Create the actual device
864 //
865 Status = RamdiskCreateDiskDevice(DeviceExtension,
866 Input,
867 ValidateOnly,
868 &DriveExtension);
869 if (NT_SUCCESS(Status))
870 {
871 //
872 // Invalidate and set success
873 //
874 IoInvalidateDeviceRelations(DeviceExtension->PhysicalDeviceObject, 0);
875 Irp->IoStatus.Information = STATUS_SUCCESS;
876 }
877
878 //
879 // We're done
880 //
881 return Status;
882 }
883
884 NTSTATUS
885 NTAPI
886 RamdiskGetPartitionInfo(IN PIRP Irp,
887 IN PRAMDISK_DRIVE_EXTENSION DeviceExtension)
888 {
889 NTSTATUS Status;
890 PPARTITION_INFORMATION PartitionInfo;
891 PVOID BaseAddress;
892 LARGE_INTEGER Zero = {{0, 0}};
893 ULONG Length;
894 PIO_STACK_LOCATION IoStackLocation;
895
896 //
897 // Validate the length
898 //
899 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
900 if (IoStackLocation->Parameters.DeviceIoControl.
901 OutputBufferLength < sizeof(PARTITION_INFORMATION))
902 {
903 //
904 // Invalid length
905 //
906 Status = STATUS_BUFFER_TOO_SMALL;
907 Irp->IoStatus.Status = Status;
908 Irp->IoStatus.Information = 0;
909 return Status;
910 }
911
912 //
913 // Map the partition table
914 //
915 BaseAddress = RamdiskMapPages(DeviceExtension, Zero, PAGE_SIZE, &Length);
916 if (!BaseAddress)
917 {
918 //
919 // No memory
920 //
921 Status = STATUS_INSUFFICIENT_RESOURCES;
922 Irp->IoStatus.Status = Status;
923 Irp->IoStatus.Information = 0;
924 return Status;
925 }
926
927 //
928 // Fill out the information
929 //
930 PartitionInfo = Irp->AssociatedIrp.SystemBuffer;
931 PartitionInfo->StartingOffset.QuadPart = DeviceExtension->BytesPerSector;
932 PartitionInfo->PartitionLength.QuadPart = DeviceExtension->BytesPerSector *
933 DeviceExtension->SectorsPerTrack *
934 DeviceExtension->NumberOfHeads *
935 DeviceExtension->Cylinders;
936 PartitionInfo->HiddenSectors = DeviceExtension->HiddenSectors;
937 PartitionInfo->PartitionNumber = 0;
938 PartitionInfo->PartitionType = *((PCHAR)BaseAddress + 450);
939 PartitionInfo->BootIndicator = (DeviceExtension->DiskType ==
940 RAMDISK_BOOT_DISK) ? TRUE: FALSE;
941 PartitionInfo->RecognizedPartition = IsRecognizedPartition(PartitionInfo->
942 PartitionType);
943 PartitionInfo->RewritePartition = FALSE;
944
945 //
946 // Unmap the partition table
947 //
948 RamdiskUnmapPages(DeviceExtension, BaseAddress, Zero, Length);
949
950 //
951 // Done
952 //
953 Irp->IoStatus.Status = STATUS_SUCCESS;
954 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
955 return STATUS_SUCCESS;
956 }
957
958 NTSTATUS
959 NTAPI
960 RamdiskSetPartitionInfo(IN PIRP Irp,
961 IN PRAMDISK_DRIVE_EXTENSION DeviceExtension)
962 {
963 ULONG BytesRead;
964 NTSTATUS Status;
965 PVOID BaseAddress;
966 PIO_STACK_LOCATION Stack;
967 LARGE_INTEGER Zero = {{0, 0}};
968 PPARTITION_INFORMATION PartitionInfo;
969
970 //
971 // First validate input
972 //
973 Stack = IoGetCurrentIrpStackLocation(Irp);
974 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(PARTITION_INFORMATION))
975 {
976 Status = STATUS_INVALID_PARAMETER;
977 goto SetAndQuit;
978 }
979
980 //
981 // Map to get MBR
982 //
983 BaseAddress = RamdiskMapPages(DeviceExtension, Zero, PAGE_SIZE, &BytesRead);
984 if (BaseAddress == NULL)
985 {
986 Status = STATUS_INSUFFICIENT_RESOURCES;
987 goto SetAndQuit;
988 }
989
990 //
991 // Set the new partition type
992 // On partition 0, field system indicator
993 //
994 PartitionInfo = (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
995 *((PCHAR)BaseAddress + 450) = PartitionInfo->PartitionType;
996
997 //
998 // And unmap
999 //
1000 RamdiskUnmapPages(DeviceExtension, BaseAddress, Zero, BytesRead);
1001 Status = STATUS_SUCCESS;
1002
1003 SetAndQuit:
1004 Irp->IoStatus.Status = Status;
1005 Irp->IoStatus.Information = 0;
1006 return Status;
1007 }
1008
1009 VOID
1010 NTAPI
1011 RamdiskWorkerThread(IN PDEVICE_OBJECT DeviceObject,
1012 IN PVOID Context)
1013 {
1014 PRAMDISK_BUS_EXTENSION DeviceExtension;
1015 NTSTATUS Status;
1016 PIO_STACK_LOCATION IoStackLocation;
1017 PIRP Irp = Context;
1018
1019 //
1020 // Get the stack location
1021 //
1022 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
1023
1024 //
1025 // Free the work item
1026 //
1027 IoFreeWorkItem(Irp->Tail.Overlay.DriverContext[0]);
1028
1029 //
1030 // Grab the device extension and lock it
1031 //
1032 DeviceExtension = DeviceObject->DeviceExtension;
1033 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Irp);
1034 if (NT_SUCCESS(Status))
1035 {
1036 //
1037 // Discriminate by major code
1038 //
1039 switch (IoStackLocation->MajorFunction)
1040 {
1041 //
1042 // Device control
1043 //
1044 case IRP_MJ_DEVICE_CONTROL:
1045
1046 //
1047 // Let's take a look at the IOCTL
1048 //
1049 switch (IoStackLocation->Parameters.DeviceIoControl.IoControlCode)
1050 {
1051 //
1052 // Ramdisk create request
1053 //
1054 case FSCTL_CREATE_RAM_DISK:
1055
1056 //
1057 // This time we'll do it for real
1058 //
1059 Status = RamdiskCreateRamdisk(DeviceObject, Irp, FALSE);
1060 break;
1061
1062 case IOCTL_DISK_SET_PARTITION_INFO:
1063
1064 Status = RamdiskSetPartitionInfo(Irp, (PRAMDISK_DRIVE_EXTENSION)DeviceExtension);
1065 break;
1066
1067 case IOCTL_DISK_GET_DRIVE_LAYOUT:
1068
1069 DPRINT1("Get drive layout request\n");
1070 UNIMPLEMENTED;
1071 ASSERT(FALSE); // while (TRUE);
1072 break;
1073
1074 case IOCTL_DISK_GET_PARTITION_INFO:
1075
1076 Status = RamdiskGetPartitionInfo(Irp, (PRAMDISK_DRIVE_EXTENSION)DeviceExtension);
1077 break;
1078
1079 default:
1080
1081 DPRINT1("Invalid request\n");
1082 UNIMPLEMENTED;
1083 ASSERT(FALSE); // while (TRUE);
1084 break;
1085 }
1086
1087 //
1088 // We're here
1089 //
1090 break;
1091
1092 //
1093 // Read or write request
1094 //
1095 case IRP_MJ_READ:
1096 case IRP_MJ_WRITE:
1097
1098 DPRINT1("Read/Write request\n");
1099 UNIMPLEMENTED;
1100 ASSERT(FALSE); // while (TRUE);
1101 break;
1102
1103 //
1104 // Internal request (SCSI?)
1105 //
1106 case IRP_MJ_INTERNAL_DEVICE_CONTROL:
1107
1108 DPRINT1("SCSI request\n");
1109 UNIMPLEMENTED;
1110 ASSERT(FALSE); // while (TRUE);
1111 break;
1112
1113 //
1114 // Flush request
1115 //
1116 case IRP_MJ_FLUSH_BUFFERS:
1117
1118 DPRINT1("Flush request\n");
1119 UNIMPLEMENTED;
1120 ASSERT(FALSE); // while (TRUE);
1121 break;
1122
1123 //
1124 // Anything else
1125 //
1126 default:
1127
1128 DPRINT1("Invalid request: %lx\n", IoStackLocation->MajorFunction);
1129 UNIMPLEMENTED;
1130 ASSERT(FALSE); // while (TRUE);
1131 break;
1132 }
1133
1134 //
1135 // Complete the I/O
1136 //
1137 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp);
1138 Irp->IoStatus.Status = Status;
1139 Irp->IoStatus.Information = 0;
1140 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1141 return;
1142 }
1143
1144 //
1145 // Fail the I/O
1146 //
1147 Irp->IoStatus.Status = Status;
1148 Irp->IoStatus.Information = 0;
1149 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1150 }
1151
1152 NTSTATUS
1153 NTAPI
1154 SendIrpToThread(IN PDEVICE_OBJECT DeviceObject,
1155 IN PIRP Irp)
1156 {
1157 PIO_WORKITEM WorkItem;
1158
1159 //
1160 // Mark the IRP pending
1161 //
1162 IoMarkIrpPending(Irp);
1163
1164 //
1165 // Allocate a work item
1166 //
1167 WorkItem = IoAllocateWorkItem(DeviceObject);
1168 if (WorkItem)
1169 {
1170 //
1171 // Queue it up
1172 //
1173 Irp->Tail.Overlay.DriverContext[0] = WorkItem;
1174 IoQueueWorkItem(WorkItem, RamdiskWorkerThread, DelayedWorkQueue, Irp);
1175 return STATUS_PENDING;
1176 }
1177 else
1178 {
1179 //
1180 // Fail
1181 //
1182 return STATUS_INSUFFICIENT_RESOURCES;
1183 }
1184 }
1185
1186 NTSTATUS
1187 NTAPI
1188 RamdiskReadWriteReal(IN PIRP Irp,
1189 IN PRAMDISK_DRIVE_EXTENSION DeviceExtension)
1190 {
1191 PMDL Mdl;
1192 PVOID CurrentBase, SystemVa, BaseAddress;
1193 PIO_STACK_LOCATION IoStackLocation;
1194 LARGE_INTEGER CurrentOffset;
1195 ULONG BytesRead, BytesLeft, CopyLength;
1196 PVOID Source, Destination;
1197 NTSTATUS Status;
1198
1199 //
1200 // Get the MDL and check if it's mapped
1201 //
1202 Mdl = Irp->MdlAddress;
1203 if (Mdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA | MDL_SOURCE_IS_NONPAGED_POOL))
1204 {
1205 //
1206 // Use the mapped address
1207 //
1208 SystemVa = Mdl->MappedSystemVa;
1209 }
1210 else
1211 {
1212 //
1213 // Map it ourselves
1214 //
1215 SystemVa = MmMapLockedPagesSpecifyCache(Mdl,
1216 0,
1217 MmCached,
1218 NULL,
1219 0,
1220 NormalPagePriority);
1221 }
1222
1223 //
1224 // Make sure we were able to map it
1225 //
1226 CurrentBase = SystemVa;
1227 if (!SystemVa) return STATUS_INSUFFICIENT_RESOURCES;
1228
1229 //
1230 // Initialize default
1231 //
1232 Irp->IoStatus.Information = 0;
1233
1234 //
1235 // Get the I/O Stack Location and capture the data
1236 //
1237 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
1238 CurrentOffset = IoStackLocation->Parameters.Read.ByteOffset;
1239 BytesLeft = IoStackLocation->Parameters.Read.Length;
1240 if (!BytesLeft) return STATUS_INVALID_PARAMETER;
1241
1242 //
1243 // Do the copy loop
1244 //
1245 while (TRUE)
1246 {
1247 //
1248 // Map the pages
1249 //
1250 BaseAddress = RamdiskMapPages(DeviceExtension,
1251 CurrentOffset,
1252 BytesLeft,
1253 &BytesRead);
1254 if (!BaseAddress) return STATUS_INSUFFICIENT_RESOURCES;
1255
1256 //
1257 // Update our lengths
1258 //
1259 Irp->IoStatus.Information += BytesRead;
1260 CopyLength = BytesRead;
1261
1262 //
1263 // Check if this was a read or write
1264 //
1265 Status = STATUS_SUCCESS;
1266 if (IoStackLocation->MajorFunction == IRP_MJ_READ)
1267 {
1268 //
1269 // Set our copy parameters
1270 //
1271 Destination = CurrentBase;
1272 Source = BaseAddress;
1273 goto DoCopy;
1274 }
1275 else if (IoStackLocation->MajorFunction == IRP_MJ_WRITE)
1276 {
1277 //
1278 // Set our copy parameters
1279 //
1280 Destination = BaseAddress;
1281 Source = CurrentBase;
1282 DoCopy:
1283 //
1284 // Copy the data
1285 //
1286 RtlCopyMemory(Destination, Source, CopyLength);
1287 }
1288 else
1289 {
1290 //
1291 // Prepare us for failure
1292 //
1293 BytesLeft = CopyLength;
1294 Status = STATUS_INVALID_PARAMETER;
1295 }
1296
1297 //
1298 // Unmap the pages
1299 //
1300 RamdiskUnmapPages(DeviceExtension,
1301 BaseAddress,
1302 CurrentOffset,
1303 BytesRead);
1304
1305 //
1306 // Update offset and bytes left
1307 //
1308 BytesLeft -= BytesRead;
1309 CurrentOffset.QuadPart += BytesRead;
1310 CurrentBase = (PVOID)((ULONG_PTR)CurrentBase + BytesRead);
1311
1312 //
1313 // Check if we're done
1314 //
1315 if (!BytesLeft) return Status;
1316 }
1317 }
1318
1319 NTSTATUS
1320 NTAPI
1321 RamdiskOpenClose(IN PDEVICE_OBJECT DeviceObject,
1322 IN PIRP Irp)
1323 {
1324 //
1325 // Complete the IRP
1326 //
1327 Irp->IoStatus.Information = 1;
1328 Irp->IoStatus.Status = STATUS_SUCCESS;
1329 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1330 return STATUS_SUCCESS;
1331 }
1332
1333 NTSTATUS
1334 NTAPI
1335 RamdiskReadWrite(IN PDEVICE_OBJECT DeviceObject,
1336 IN PIRP Irp)
1337 {
1338 PRAMDISK_DRIVE_EXTENSION DeviceExtension;
1339 //ULONG Length;
1340 //LARGE_INTEGER ByteOffset;
1341 PIO_STACK_LOCATION IoStackLocation;
1342 NTSTATUS Status, ReturnStatus;
1343
1344 //
1345 // Get the device extension and make sure this isn't a bus
1346 //
1347 DeviceExtension = DeviceObject->DeviceExtension;
1348 if (DeviceExtension->Type == RamdiskBus)
1349 {
1350 //
1351 // Fail
1352 //
1353 Status = STATUS_INVALID_DEVICE_REQUEST;
1354 goto Complete;
1355 }
1356
1357 //
1358 // Capture parameters
1359 //
1360 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
1361 //Length = IoStackLocation->Parameters.Read.Length;
1362 //ByteOffset = IoStackLocation->Parameters.Read.ByteOffset;
1363
1364 //
1365 // FIXME: Validate offset
1366 //
1367
1368 //
1369 // FIXME: Validate sector
1370 //
1371
1372 //
1373 // Validate write
1374 //
1375 if ((IoStackLocation->MajorFunction == IRP_MJ_WRITE) &&
1376 (DeviceExtension->DiskOptions.Readonly))
1377 {
1378 //
1379 // Fail, this is read-only
1380 //
1381 Status = STATUS_MEDIA_WRITE_PROTECTED;
1382 goto Complete;
1383 }
1384
1385 //
1386 // See if we want to do this sync or async
1387 //
1388 if (DeviceExtension->DiskType > RAMDISK_MEMORY_MAPPED_DISK)
1389 {
1390 //
1391 // Do it sync
1392 //
1393 Status = RamdiskReadWriteReal(Irp, DeviceExtension);
1394 goto Complete;
1395 }
1396
1397 //
1398 // Queue it to the worker
1399 //
1400 Status = SendIrpToThread(DeviceObject, Irp);
1401 ReturnStatus = STATUS_PENDING;
1402
1403 //
1404 // Check if we're pending or not
1405 //
1406 if (Status != STATUS_PENDING)
1407 {
1408 Complete:
1409 //
1410 // Complete the IRP
1411 //
1412 Irp->IoStatus.Status = Status;
1413 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1414 ReturnStatus = Status;
1415 }
1416
1417 //
1418 // Return to caller
1419 //
1420 return ReturnStatus;
1421 }
1422
1423 NTSTATUS
1424 NTAPI
1425 RamdiskDeviceControl(IN PDEVICE_OBJECT DeviceObject,
1426 IN PIRP Irp)
1427 {
1428 NTSTATUS Status;
1429 PIO_STACK_LOCATION IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
1430 PRAMDISK_BUS_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
1431 PRAMDISK_DRIVE_EXTENSION DriveExtension = (PVOID)DeviceExtension;
1432 ULONG Information;
1433 PCDROM_TOC Toc;
1434 PDISK_GEOMETRY DiskGeometry;
1435
1436 //
1437 // Grab the remove lock
1438 //
1439 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Irp);
1440 if (!NT_SUCCESS(Status))
1441 {
1442 //
1443 // Fail the IRP
1444 //
1445 Irp->IoStatus.Information = 0;
1446 Irp->IoStatus.Status = Status;
1447 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1448 return Status;
1449 }
1450
1451 //
1452 // Setup some defaults
1453 //
1454 Status = STATUS_INVALID_DEVICE_REQUEST;
1455 Information = 0;
1456
1457 //
1458 // Check if this is an bus device or the drive
1459 //
1460 if (DeviceExtension->Type == RamdiskBus)
1461 {
1462 //
1463 // Check what the request is
1464 //
1465 switch (IoStackLocation->Parameters.DeviceIoControl.IoControlCode)
1466 {
1467 //
1468 // Request to create a ramdisk
1469 //
1470 case FSCTL_CREATE_RAM_DISK:
1471
1472 //
1473 // Do it
1474 //
1475 Status = RamdiskCreateRamdisk(DeviceObject, Irp, TRUE);
1476 if (!NT_SUCCESS(Status)) goto CompleteRequest;
1477 break;
1478
1479 default:
1480
1481 //
1482 // We don't handle anything else yet
1483 //
1484 ASSERT(FALSE); // while (TRUE);
1485 }
1486 }
1487 else
1488 {
1489 //
1490 // Check what the request is
1491 //
1492 switch (IoStackLocation->Parameters.DeviceIoControl.IoControlCode)
1493 {
1494 case IOCTL_DISK_CHECK_VERIFY:
1495 case IOCTL_STORAGE_CHECK_VERIFY:
1496 case IOCTL_STORAGE_CHECK_VERIFY2:
1497 case IOCTL_CDROM_CHECK_VERIFY:
1498
1499 UNIMPLEMENTED;
1500 ASSERT(FALSE); // while (TRUE);
1501 break;
1502
1503 case IOCTL_STORAGE_GET_MEDIA_TYPES:
1504 case IOCTL_DISK_GET_MEDIA_TYPES:
1505 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
1506 case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
1507
1508 //
1509 // Validate the length
1510 //
1511 if (IoStackLocation->Parameters.DeviceIoControl.
1512 OutputBufferLength < sizeof(DISK_GEOMETRY))
1513 {
1514 //
1515 // Invalid length
1516 //
1517 Status = STATUS_BUFFER_TOO_SMALL;
1518 break;
1519 }
1520
1521 //
1522 // Fill it out
1523 //
1524 DiskGeometry = Irp->AssociatedIrp.SystemBuffer;
1525 DiskGeometry->Cylinders.QuadPart = DriveExtension->Cylinders;
1526 DiskGeometry->BytesPerSector = DriveExtension->BytesPerSector;
1527 DiskGeometry->SectorsPerTrack = DriveExtension->SectorsPerTrack;
1528 DiskGeometry->TracksPerCylinder = DriveExtension->NumberOfHeads;
1529 DiskGeometry->MediaType = DriveExtension->DiskOptions.Fixed ?
1530 FixedMedia : RemovableMedia;
1531
1532 //
1533 // We're done
1534 //
1535 Status = STATUS_SUCCESS;
1536 Information = sizeof(DISK_GEOMETRY);
1537 break;
1538
1539 //
1540 // Hack to support ReactOS's broken CDFS
1541 //
1542 case IOCTL_CDROM_GET_LAST_SESSION:
1543
1544 //
1545 // Validate the length
1546 //
1547 if (IoStackLocation->Parameters.DeviceIoControl.
1548 OutputBufferLength < RAMDISK_SESSION_SIZE)
1549 {
1550 //
1551 // Invalid length
1552 //
1553 Status = STATUS_BUFFER_TOO_SMALL;
1554 break;
1555 }
1556
1557 //
1558 // Fill out the TOC
1559 //
1560 Toc = Irp->AssociatedIrp.SystemBuffer;
1561 Toc->Length[0] = 0;
1562 Toc->Length[1] = RAMDISK_SESSION_SIZE - sizeof(Toc->Length);
1563 Toc->FirstTrack = 1;
1564 Toc->LastTrack = 1;
1565 Toc->TrackData[0].Adr = 1;
1566 Toc->TrackData[0].Control = TOC_DATA_TRACK;
1567 Toc->TrackData[0].TrackNumber = 1;
1568 Toc->TrackData[0].Address[0] =
1569 Toc->TrackData[0].Address[1] =
1570 Toc->TrackData[0].Address[2] =
1571 Toc->TrackData[0].Address[3] = 0;
1572
1573 //
1574 // We're done
1575 //
1576 Status = STATUS_SUCCESS;
1577 Information = RAMDISK_SESSION_SIZE;
1578 break;
1579
1580 case IOCTL_CDROM_READ_TOC:
1581
1582 //
1583 // Validate the length
1584 //
1585 if (IoStackLocation->Parameters.DeviceIoControl.
1586 OutputBufferLength < sizeof(CDROM_TOC))
1587 {
1588 //
1589 // Invalid length
1590 //
1591 Status = STATUS_BUFFER_TOO_SMALL;
1592 break;
1593 }
1594
1595 //
1596 // Clear the TOC
1597 //
1598 Toc = Irp->AssociatedIrp.SystemBuffer;
1599 RtlZeroMemory(Toc, sizeof(CDROM_TOC));
1600
1601 //
1602 // Fill it out
1603 //
1604 Toc->Length[0] = 0;
1605 Toc->Length[1] = RAMDISK_TOC_SIZE - sizeof(Toc->Length);
1606 Toc->FirstTrack = 1;
1607 Toc->LastTrack = 1;
1608 Toc->TrackData[0].Adr = 1;
1609 Toc->TrackData[0].Control = TOC_DATA_TRACK;
1610 Toc->TrackData[0].TrackNumber = 1;
1611
1612 //
1613 // We're done
1614 //
1615 Status = STATUS_SUCCESS;
1616 Information = RAMDISK_TOC_SIZE;
1617 break;
1618
1619 case IOCTL_DISK_SET_PARTITION_INFO:
1620
1621 Status = RamdiskSetPartitionInfo(Irp, DriveExtension);
1622 break;
1623
1624 case IOCTL_DISK_GET_PARTITION_INFO:
1625
1626 //
1627 // Validate the length
1628 //
1629 if (IoStackLocation->Parameters.DeviceIoControl.
1630 OutputBufferLength < sizeof(PARTITION_INFORMATION))
1631 {
1632 //
1633 // Invalid length
1634 //
1635 Status = STATUS_BUFFER_TOO_SMALL;
1636 break;
1637 }
1638
1639 //
1640 // Check if we need to do this sync or async
1641 //
1642 if (DriveExtension->DiskType > RAMDISK_MEMORY_MAPPED_DISK)
1643 {
1644 //
1645 // Call the helper function
1646 //
1647 Status = RamdiskGetPartitionInfo(Irp, DriveExtension);
1648 }
1649 else
1650 {
1651 //
1652 // Do it asynchronously later
1653 //
1654 goto CallWorker;
1655 }
1656
1657 //
1658 // We're done
1659 //
1660 Information = Irp->IoStatus.Information;
1661 break;
1662
1663 case IOCTL_DISK_GET_DRIVE_LAYOUT:
1664
1665 UNIMPLEMENTED;
1666 ASSERT(FALSE); // while (TRUE);
1667 break;
1668
1669 case IOCTL_DISK_GET_LENGTH_INFO:
1670
1671 UNIMPLEMENTED;
1672 ASSERT(FALSE); // while (TRUE);
1673 break;
1674
1675 case IOCTL_DISK_IS_WRITABLE:
1676
1677 UNIMPLEMENTED;
1678 ASSERT(FALSE); // while (TRUE);
1679 break;
1680
1681 case IOCTL_SCSI_MINIPORT:
1682
1683 UNIMPLEMENTED;
1684 ASSERT(FALSE); // while (TRUE);
1685 break;
1686
1687 case IOCTL_STORAGE_QUERY_PROPERTY:
1688
1689 UNIMPLEMENTED;
1690 ASSERT(FALSE); // while (TRUE);
1691 break;
1692
1693 case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID:
1694
1695 UNIMPLEMENTED;
1696 ASSERT(FALSE); // while (TRUE);
1697 break;
1698
1699 case IOCTL_MOUNTDEV_QUERY_STABLE_GUID:
1700
1701 UNIMPLEMENTED;
1702 ASSERT(FALSE); // while (TRUE);
1703 break;
1704
1705 case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS:
1706
1707 UNIMPLEMENTED;
1708 ASSERT(FALSE); // while (TRUE);
1709 break;
1710
1711 case IOCTL_VOLUME_SET_GPT_ATTRIBUTES:
1712
1713 UNIMPLEMENTED;
1714 ASSERT(FALSE); // while (TRUE);
1715 break;
1716
1717 case IOCTL_VOLUME_GET_GPT_ATTRIBUTES:
1718
1719 UNIMPLEMENTED;
1720 ASSERT(FALSE); // while (TRUE);
1721 break;
1722
1723 case IOCTL_VOLUME_OFFLINE:
1724
1725 UNIMPLEMENTED;
1726 ASSERT(FALSE); // while (TRUE);
1727 break;
1728
1729 default:
1730
1731 //
1732 // Drive code not emulated
1733 //
1734 DPRINT1("IOCTL: %lx\n", IoStackLocation->Parameters.DeviceIoControl.IoControlCode);
1735 break;
1736 }
1737
1738 //
1739 // If requests drop down here, we just return them complete them
1740 //
1741 goto CompleteRequest;
1742 }
1743
1744 //
1745 // Queue the request to our worker thread
1746 //
1747 CallWorker:
1748 Status = SendIrpToThread(DeviceObject, Irp);
1749
1750 CompleteRequest:
1751 //
1752 // Release the lock
1753 //
1754 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp);
1755 if (Status != STATUS_PENDING)
1756 {
1757 //
1758 // Complete the request
1759 //
1760 Irp->IoStatus.Status = Status;
1761 Irp->IoStatus.Information = Information;
1762 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1763 }
1764
1765 //
1766 // Return status
1767 //
1768 return Status;
1769 }
1770
1771 NTSTATUS
1772 NTAPI
1773 RamdiskQueryDeviceRelations(IN DEVICE_RELATION_TYPE Type,
1774 IN PDEVICE_OBJECT DeviceObject,
1775 IN PIRP Irp)
1776 {
1777 PRAMDISK_BUS_EXTENSION DeviceExtension;
1778 PRAMDISK_DRIVE_EXTENSION DriveExtension;
1779 PDEVICE_RELATIONS DeviceRelations, OurDeviceRelations;
1780 ULONG Count, DiskCount, FinalCount;
1781 PLIST_ENTRY ListHead, NextEntry;
1782 PDEVICE_OBJECT* DriveDeviceObject;
1783 RAMDISK_DEVICE_STATE State;
1784
1785 //
1786 // Get the device extension and check if this is a drive
1787 //
1788 DeviceExtension = DeviceObject->DeviceExtension;
1789 if (DeviceExtension->Type == RamdiskDrive)
1790 {
1791 //
1792 // FIXME: TODO
1793 //
1794 UNIMPLEMENTED;
1795 ASSERT(FALSE); // while (TRUE);
1796 }
1797
1798 //
1799 // Anything but bus relations, we don't handle
1800 //
1801 if (Type) goto PassToNext;
1802
1803 //
1804 // Acquire the disk list lock
1805 //
1806 KeEnterCriticalRegion();
1807 ExAcquireFastMutex(&DeviceExtension->DiskListLock);
1808
1809 //
1810 // Did a device already fill relations?
1811 //
1812 DeviceRelations = (PDEVICE_RELATIONS)Irp->IoStatus.Information;
1813 if (DeviceRelations)
1814 {
1815 //
1816 // Use the data
1817 //
1818 Count = DeviceRelations->Count;
1819 }
1820 else
1821 {
1822 //
1823 // We're the first
1824 //
1825 Count = 0;
1826 }
1827
1828 //
1829 // Now loop our drives
1830 //
1831 DiskCount = 0;
1832 ListHead = &DeviceExtension->DiskList;
1833 NextEntry = ListHead->Flink;
1834 while (NextEntry != ListHead)
1835 {
1836 //
1837 // As long as it wasn't removed, count it in
1838 //
1839 DriveExtension = CONTAINING_RECORD(NextEntry,
1840 RAMDISK_DRIVE_EXTENSION,
1841 DiskList);
1842 if (DriveExtension->State < RamdiskStateBusRemoved) DiskCount++;
1843
1844 //
1845 // Move to the next one
1846 //
1847 NextEntry = NextEntry->Flink;
1848 }
1849
1850 //
1851 // Now we know our final count
1852 //
1853 FinalCount = Count + DiskCount;
1854
1855 //
1856 // Allocate the structure
1857 //
1858 OurDeviceRelations = ExAllocatePoolWithTag(PagedPool,
1859 FIELD_OFFSET(DEVICE_RELATIONS,
1860 Objects) +
1861 FinalCount *
1862 sizeof(PDEVICE_OBJECT),
1863 'dmaR');
1864 if (!OurDeviceRelations)
1865 {
1866 //
1867 // Fail
1868 //
1869 ExReleaseFastMutex(&DeviceExtension->DiskListLock);
1870 KeLeaveCriticalRegion();
1871 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1872 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1873 return STATUS_INSUFFICIENT_RESOURCES;
1874 }
1875
1876 //
1877 // Check if we already had some relations
1878 //
1879 if (Count)
1880 {
1881 //
1882 // Copy them in
1883 //
1884 RtlCopyMemory(OurDeviceRelations->Objects,
1885 DeviceRelations->Objects,
1886 Count * sizeof(PDEVICE_OBJECT));
1887 }
1888
1889 //
1890 // Save the count
1891 //
1892 OurDeviceRelations->Count = FinalCount;
1893
1894 //
1895 // Now loop our drives again
1896 //
1897 ListHead = &DeviceExtension->DiskList;
1898 NextEntry = ListHead->Flink;
1899 while (NextEntry != ListHead)
1900 {
1901 //
1902 // Go to the end of the list
1903 //
1904 DriveDeviceObject = &OurDeviceRelations->Objects[Count];
1905
1906 //
1907 // Get the drive state
1908 //
1909 DriveExtension = CONTAINING_RECORD(NextEntry,
1910 RAMDISK_DRIVE_EXTENSION,
1911 DiskList);
1912 State = DriveExtension->State;
1913
1914 //
1915 // If it was removed or enumerated, we don't touch the device object
1916 //
1917 if (State >= RamdiskStateBusRemoved)
1918 {
1919 //
1920 // If it was removed, we still have to keep track of this though
1921 //
1922 if (State == RamdiskStateBusRemoved)
1923 {
1924 //
1925 // Mark it as enumerated now, but don't actually reference it
1926 //
1927 DriveExtension->State = RamdiskStateEnumerated;
1928 }
1929 }
1930 else
1931 {
1932 //
1933 // First time it's enumerated, reference the device object
1934 //
1935 ObReferenceObject(DriveExtension->DeviceObject);
1936
1937 //
1938 // Save the object pointer, and move on
1939 //
1940 *DriveDeviceObject++ = DriveExtension->DeviceObject;
1941 }
1942
1943 if (DriveExtension->State < RamdiskStateBusRemoved) DiskCount++;
1944
1945 //
1946 // Move to the next one
1947 //
1948 NextEntry = NextEntry->Flink;
1949 }
1950
1951 //
1952 // Release the lock
1953 //
1954 ExReleaseFastMutex(&DeviceExtension->DiskListLock);
1955 KeLeaveCriticalRegion();
1956
1957 //
1958 // Cleanup old relations
1959 //
1960 if (DeviceRelations) ExFreePool(DeviceRelations);
1961
1962 //
1963 // Complete our IRP
1964 //
1965 Irp->IoStatus.Information = (ULONG_PTR)OurDeviceRelations;
1966 Irp->IoStatus.Status = STATUS_SUCCESS;
1967
1968 //
1969 // Pass to the next driver
1970 //
1971 PassToNext:
1972 IoCopyCurrentIrpStackLocationToNext(Irp);
1973 return IoCallDriver(DeviceExtension->AttachedDevice, Irp);
1974 }
1975
1976 NTSTATUS
1977 NTAPI
1978 RamdiskDeleteDiskDevice(IN PDEVICE_OBJECT DeviceObject,
1979 IN PIRP Irp)
1980 {
1981 UNIMPLEMENTED;
1982 ASSERT(FALSE); // while (TRUE);
1983 return STATUS_SUCCESS;
1984 }
1985
1986 NTSTATUS
1987 NTAPI
1988 RamdiskRemoveBusDevice(IN PDEVICE_OBJECT DeviceObject,
1989 IN PIRP Irp)
1990 {
1991 NTSTATUS Status;
1992 PLIST_ENTRY ListHead, NextEntry;
1993 PRAMDISK_BUS_EXTENSION DeviceExtension;
1994 PRAMDISK_DRIVE_EXTENSION DriveExtension;
1995
1996 DeviceExtension = DeviceObject->DeviceExtension;
1997
1998 //
1999 // Acquire disks list lock
2000 //
2001 KeEnterCriticalRegion();
2002 ExAcquireFastMutex(&DeviceExtension->DiskListLock);
2003
2004 //
2005 // Loop over drives
2006 //
2007 ListHead = &DeviceExtension->DiskList;
2008 NextEntry = ListHead->Flink;
2009 while (NextEntry != ListHead)
2010 {
2011 DriveExtension = CONTAINING_RECORD(NextEntry,
2012 RAMDISK_DRIVE_EXTENSION,
2013 DiskList);
2014
2015 //
2016 // Delete the disk
2017 //
2018 IoAcquireRemoveLock(&DriveExtension->RemoveLock, NULL);
2019 RamdiskDeleteDiskDevice(DriveExtension->PhysicalDeviceObject, NULL);
2020
2021 //
2022 // RamdiskDeleteDiskDevice releases list lock, so reacquire it
2023 //
2024 KeEnterCriticalRegion();
2025 ExAcquireFastMutex(&DeviceExtension->DiskListLock);
2026 }
2027
2028 //
2029 // Release disks list lock
2030 //
2031 ExReleaseFastMutex(&DeviceExtension->DiskListLock);
2032 KeLeaveCriticalRegion();
2033
2034 //
2035 // Prepare to pass to the lower driver
2036 //
2037 IoSkipCurrentIrpStackLocation(Irp);
2038 //
2039 // Here everything went fine
2040 //
2041 Irp->IoStatus.Status = STATUS_SUCCESS;
2042
2043 //
2044 // Call lower driver
2045 //
2046 Status = IoCallDriver(DeviceExtension->AttachedDevice, Irp);
2047
2048 //
2049 // Update state
2050 //
2051 DeviceExtension->State = RamdiskStateBusRemoved;
2052
2053 //
2054 // Release the lock, and ensure that everyone
2055 // has finished its job before we continue
2056 // The lock has been acquired by the dispatcher
2057 //
2058 IoReleaseRemoveLockAndWait(&DeviceExtension->RemoveLock, Irp);
2059
2060 //
2061 // If there's a drive name
2062 //
2063 if (DeviceExtension->DriveDeviceName.Buffer)
2064 {
2065 //
2066 // Inform it's going to be disabled
2067 // and free the drive name
2068 //
2069 IoSetDeviceInterfaceState(&DeviceExtension->DriveDeviceName, FALSE);
2070 RtlFreeUnicodeString(&DeviceExtension->DriveDeviceName);
2071 }
2072
2073 //
2074 // Part from the stack, detach from lower device
2075 //
2076 IoDetachDevice(DeviceExtension->AttachedDevice);
2077
2078 //
2079 // Finally, delete device
2080 //
2081 RamdiskBusFdo = NULL;
2082 IoDeleteDevice(DeviceObject);
2083
2084 //
2085 // Return status from lower driver
2086 //
2087 return Status;
2088 }
2089
2090 NTSTATUS
2091 NTAPI
2092 RamdiskPnp(IN PDEVICE_OBJECT DeviceObject,
2093 IN PIRP Irp)
2094 {
2095 PIO_STACK_LOCATION IoStackLocation;
2096 PRAMDISK_BUS_EXTENSION DeviceExtension;
2097 NTSTATUS Status;
2098 UCHAR Minor;
2099
2100 //
2101 // Get the device extension and stack location
2102 //
2103 DeviceExtension = DeviceObject->DeviceExtension;
2104 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
2105 Minor = IoStackLocation->MinorFunction;
2106
2107 //
2108 // Check if the bus is removed
2109 //
2110 if (DeviceExtension->State == RamdiskStateBusRemoved)
2111 {
2112 //
2113 // Only remove-device and query-id are allowed
2114 //
2115 if ((Minor != IRP_MN_REMOVE_DEVICE) && (Minor != IRP_MN_QUERY_ID))
2116 {
2117 //
2118 // Fail anything else
2119 //
2120 Status = STATUS_NO_SUCH_DEVICE;
2121 Irp->IoStatus.Status = Status;
2122 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2123 return Status;
2124 }
2125 }
2126
2127 //
2128 // Acquire the remove lock
2129 //
2130 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Irp);
2131 if (!NT_SUCCESS(Status))
2132 {
2133 //
2134 // Fail the IRP
2135 //
2136 Irp->IoStatus.Information = 0;
2137 Irp->IoStatus.Status = Status;
2138 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2139 return Status;
2140 }
2141
2142 //
2143 // Query the IRP type
2144 //
2145 switch (Minor)
2146 {
2147 case IRP_MN_START_DEVICE:
2148
2149 DPRINT1("PnP IRP: %lx\n", Minor);
2150 ASSERT(FALSE); // while (TRUE);
2151 break;
2152
2153 case IRP_MN_QUERY_STOP_DEVICE:
2154
2155 DPRINT1("PnP IRP: %lx\n", Minor);
2156 ASSERT(FALSE); // while (TRUE);
2157 break;
2158
2159 case IRP_MN_CANCEL_STOP_DEVICE:
2160
2161 DPRINT1("PnP IRP: %lx\n", Minor);
2162 ASSERT(FALSE); // while (TRUE);
2163 break;
2164
2165 case IRP_MN_STOP_DEVICE:
2166
2167 DPRINT1("PnP IRP: %lx\n", Minor);
2168 ASSERT(FALSE); // while (TRUE);
2169 break;
2170
2171 case IRP_MN_QUERY_REMOVE_DEVICE:
2172
2173 DPRINT1("PnP IRP: %lx\n", Minor);
2174 ASSERT(FALSE); // while (TRUE);
2175 break;
2176
2177 case IRP_MN_CANCEL_REMOVE_DEVICE:
2178
2179 DPRINT1("PnP IRP: %lx\n", Minor);
2180 ASSERT(FALSE); // while (TRUE);
2181 break;
2182
2183 case IRP_MN_REMOVE_DEVICE:
2184
2185 //
2186 // Remove the proper device
2187 //
2188 if (DeviceExtension->Type == RamdiskBus)
2189 {
2190 Status = RamdiskRemoveBusDevice(DeviceObject, Irp);
2191
2192 //
2193 // Return here, lower device has already been called
2194 // And remove lock released. This is needed by the function.
2195 //
2196 return Status;
2197 }
2198 else
2199 {
2200 Status = RamdiskDeleteDiskDevice(DeviceObject, Irp);
2201
2202 //
2203 // Complete the IRP here and return
2204 // Here again we don't have to release remove lock
2205 // This has already been done by the function.
2206 //
2207 Irp->IoStatus.Status = Status;
2208 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2209 return Status;
2210 }
2211
2212 case IRP_MN_SURPRISE_REMOVAL:
2213
2214 DPRINT1("PnP IRP: %lx\n", Minor);
2215 ASSERT(FALSE); // while (TRUE);
2216 break;
2217
2218 case IRP_MN_QUERY_ID:
2219
2220 //
2221 // Are we a drive?
2222 //
2223 if (DeviceExtension->Type == RamdiskDrive)
2224 {
2225 DPRINT1("PnP IRP: %lx\n", Minor);
2226 ASSERT(FALSE); // while (TRUE);
2227 }
2228 break;
2229
2230 case IRP_MN_QUERY_BUS_INFORMATION:
2231
2232 //
2233 // Are we a drive?
2234 //
2235 if (DeviceExtension->Type == RamdiskDrive)
2236 {
2237 DPRINT1("PnP IRP: %lx\n", Minor);
2238 ASSERT(FALSE); // while (TRUE);
2239 }
2240 break;
2241
2242 case IRP_MN_EJECT:
2243
2244 DPRINT1("PnP IRP: %lx\n", Minor);
2245 ASSERT(FALSE); // while (TRUE);
2246 break;
2247
2248 case IRP_MN_QUERY_DEVICE_TEXT:
2249
2250 //
2251 // Are we a drive?
2252 //
2253 if (DeviceExtension->Type == RamdiskDrive)
2254 {
2255 DPRINT1("PnP IRP: %lx\n", Minor);
2256 ASSERT(FALSE); // while (TRUE);
2257 }
2258 break;
2259
2260 case IRP_MN_QUERY_DEVICE_RELATIONS:
2261
2262 //
2263 // Call our main routine
2264 //
2265 Status = RamdiskQueryDeviceRelations(IoStackLocation->
2266 Parameters.
2267 QueryDeviceRelations.Type,
2268 DeviceObject,
2269 Irp);
2270 goto ReleaseAndReturn;
2271
2272 case IRP_MN_QUERY_CAPABILITIES:
2273
2274 //
2275 // Are we a drive?
2276 //
2277 if (DeviceExtension->Type == RamdiskDrive)
2278 {
2279 DPRINT1("PnP IRP: %lx\n", Minor);
2280 ASSERT(FALSE); // while (TRUE);
2281 }
2282 break;
2283
2284 case IRP_MN_QUERY_RESOURCES:
2285 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
2286
2287 //
2288 // Complete immediately without touching it
2289 //
2290 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2291 goto ReleaseAndReturn;
2292
2293 default:
2294
2295 DPRINT1("Illegal IRP: %lx\n", Minor);
2296 break;
2297 }
2298
2299 //
2300 // Are we the bus?
2301 //
2302 if (DeviceExtension->Type == RamdiskBus)
2303 {
2304 //
2305 // Do we have an attached device?
2306 //
2307 if (DeviceExtension->AttachedDevice)
2308 {
2309 //
2310 // Forward the IRP
2311 //
2312 IoSkipCurrentIrpStackLocation(Irp);
2313 Status = IoCallDriver(DeviceExtension->AttachedDevice, Irp);
2314 }
2315 }
2316
2317 //
2318 // Release the lock and return status
2319 //
2320 ReleaseAndReturn:
2321 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp);
2322 return Status;
2323 }
2324
2325 NTSTATUS
2326 NTAPI
2327 RamdiskPower(IN PDEVICE_OBJECT DeviceObject,
2328 IN PIRP Irp)
2329 {
2330 NTSTATUS Status;
2331 PIO_STACK_LOCATION IoStackLocation;
2332 PRAMDISK_BUS_EXTENSION DeviceExtension;
2333
2334 DeviceExtension = DeviceObject->DeviceExtension;
2335
2336 //
2337 // If we have a device extension, take extra caution
2338 // with the lower driver
2339 //
2340 if (DeviceExtension != NULL)
2341 {
2342 PoStartNextPowerIrp(Irp);
2343
2344 //
2345 // Device has not been removed yet, so
2346 // pass to the attached/lower driver
2347 //
2348 if (DeviceExtension->State < RamdiskStateBusRemoved)
2349 {
2350 IoSkipCurrentIrpStackLocation(Irp);
2351 return PoCallDriver(DeviceExtension->AttachedDevice, Irp);
2352 }
2353 //
2354 // Otherwise, simply complete the IRP
2355 // Notifying that deletion is pending
2356 //
2357 else
2358 {
2359 Irp->IoStatus.Status = STATUS_DELETE_PENDING;
2360 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2361 return STATUS_DELETE_PENDING;
2362 }
2363 }
2364
2365 //
2366 // Get stack and deal with minor functions
2367 //
2368 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
2369 switch (IoStackLocation->MinorFunction)
2370 {
2371 case IRP_MN_SET_POWER:
2372 //
2373 // If setting device power state
2374 // it's all fine and return success
2375 //
2376 if (DevicePowerState)
2377 {
2378 Irp->IoStatus.Status = STATUS_SUCCESS;
2379 }
2380
2381 //
2382 // Get appropriate status for return
2383 //
2384 Status = Irp->IoStatus.Status;
2385 PoStartNextPowerIrp(Irp);
2386 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2387 break;
2388
2389 case IRP_MN_QUERY_POWER:
2390 //
2391 // We can obviously accept all states
2392 // So just return success
2393 //
2394 Status =
2395 Irp->IoStatus.Status = STATUS_SUCCESS;
2396 PoStartNextPowerIrp(Irp);
2397 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2398 break;
2399
2400 default:
2401 //
2402 // Just complete and save status for return
2403 //
2404 Status = Irp->IoStatus.Status;
2405 PoStartNextPowerIrp(Irp);
2406 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2407 break;
2408 }
2409
2410 return Status;
2411 }
2412
2413 NTSTATUS
2414 NTAPI
2415 RamdiskSystemControl(IN PDEVICE_OBJECT DeviceObject,
2416 IN PIRP Irp)
2417 {
2418 NTSTATUS Status;
2419 PRAMDISK_BUS_EXTENSION DeviceExtension;
2420
2421 DeviceExtension = DeviceObject->DeviceExtension;
2422
2423 //
2424 // If we have a device extension, forward the IRP
2425 // to the attached device
2426 //
2427 if (DeviceExtension != NULL)
2428 {
2429 IoSkipCurrentIrpStackLocation(Irp);
2430 Status = IoCallDriver(DeviceExtension->AttachedDevice, Irp);
2431 }
2432 //
2433 // Otherwise just complete the request
2434 // And return the status with which we complete it
2435 //
2436 else
2437 {
2438 Status = Irp->IoStatus.Status;
2439 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2440 }
2441
2442 return Status;
2443 }
2444
2445 NTSTATUS
2446 NTAPI
2447 RamdiskScsi(IN PDEVICE_OBJECT DeviceObject,
2448 IN PIRP Irp)
2449 {
2450 NTSTATUS Status;
2451 PRAMDISK_BUS_EXTENSION DeviceExtension;
2452
2453 DeviceExtension = DeviceObject->DeviceExtension;
2454
2455 //
2456 // Having a proper device is mandatory
2457 //
2458 if (DeviceExtension->State > RamdiskStateStopped)
2459 {
2460 Status = STATUS_DEVICE_DOES_NOT_EXIST;
2461 goto CompleteIRP;
2462 }
2463
2464 //
2465 // Acquire the remove lock
2466 //
2467 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Irp);
2468 if (!NT_SUCCESS(Status))
2469 {
2470 goto CompleteIRP;
2471 }
2472
2473 //
2474 // Queue the IRP for worker
2475 //
2476 Status = SendIrpToThread(DeviceObject, Irp);
2477 if (Status != STATUS_PENDING)
2478 {
2479 goto CompleteIRP;
2480 }
2481
2482 //
2483 // Release the remove lock
2484 //
2485 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp);
2486 goto Quit;
2487
2488 CompleteIRP:
2489 Irp->IoStatus.Information = 0;
2490 Irp->IoStatus.Status = Status;
2491 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2492
2493 Quit:
2494 return Status;
2495 }
2496
2497 NTSTATUS
2498 NTAPI
2499 RamdiskFlushBuffers(IN PDEVICE_OBJECT DeviceObject,
2500 IN PIRP Irp)
2501 {
2502 NTSTATUS Status;
2503 PRAMDISK_DRIVE_EXTENSION DeviceExtension;
2504
2505 DeviceExtension = DeviceObject->DeviceExtension;
2506
2507 //
2508 // Ensure we have drive extension
2509 // Only perform flush on disks that have been created
2510 // from registry entries
2511 //
2512 if (DeviceExtension->Type != RamdiskDrive ||
2513 DeviceExtension->DiskType > RAMDISK_MEMORY_MAPPED_DISK)
2514 {
2515 Irp->IoStatus.Information = 0;
2516 Irp->IoStatus.Status = STATUS_SUCCESS;
2517 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2518 return STATUS_SUCCESS;
2519 }
2520
2521 //
2522 // Queue the IRP for worker
2523 //
2524 Status = SendIrpToThread(DeviceObject, Irp);
2525 if (Status != STATUS_PENDING)
2526 {
2527 //
2528 // Queueing failed - complete the IRP
2529 // and return failure
2530 //
2531 Irp->IoStatus.Information = 0;
2532 Irp->IoStatus.Status = Status;
2533 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2534 }
2535
2536 return Status;
2537 }
2538
2539 VOID
2540 NTAPI
2541 RamdiskUnload(IN PDRIVER_OBJECT DriverObject)
2542 {
2543 //
2544 // Just release registry path if previously allocated
2545 //
2546 if (DriverRegistryPath.Buffer)
2547 {
2548 ExFreePoolWithTag(DriverRegistryPath.Buffer, 'dmaR');
2549 }
2550 }
2551
2552 NTSTATUS
2553 NTAPI
2554 RamdiskAddDevice(IN PDRIVER_OBJECT DriverObject,
2555 IN PDEVICE_OBJECT PhysicalDeviceObject)
2556 {
2557 PRAMDISK_BUS_EXTENSION DeviceExtension;
2558 PDEVICE_OBJECT AttachedDevice;
2559 NTSTATUS Status;
2560 UNICODE_STRING DeviceName;
2561 PDEVICE_OBJECT DeviceObject;
2562
2563 //
2564 // Only create the bus FDO once
2565 //
2566 if (RamdiskBusFdo) return STATUS_DEVICE_ALREADY_ATTACHED;
2567
2568 //
2569 // Create the bus FDO
2570 //
2571 RtlInitUnicodeString(&DeviceName, L"\\Device\\Ramdisk");
2572 Status = IoCreateDevice(DriverObject,
2573 sizeof(RAMDISK_BUS_EXTENSION),
2574 &DeviceName,
2575 FILE_DEVICE_BUS_EXTENDER,
2576 FILE_DEVICE_SECURE_OPEN,
2577 0,
2578 &DeviceObject);
2579 if (NT_SUCCESS(Status))
2580 {
2581 //
2582 // Initialize the bus FDO extension
2583 //
2584 DeviceExtension = DeviceObject->DeviceExtension;
2585 RtlZeroMemory(DeviceObject->DeviceExtension,
2586 sizeof(RAMDISK_BUS_EXTENSION));
2587
2588 //
2589 // Set bus FDO flags
2590 //
2591 DeviceObject->Flags |= DO_POWER_PAGABLE | DO_DIRECT_IO;
2592
2593 //
2594 // Setup the bus FDO extension
2595 //
2596 DeviceExtension->Type = RamdiskBus;
2597 ExInitializeFastMutex(&DeviceExtension->DiskListLock);
2598 IoInitializeRemoveLock(&DeviceExtension->RemoveLock,
2599 'dmaR',
2600 0,
2601 1);
2602 InitializeListHead(&DeviceExtension->DiskList);
2603 DeviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
2604 DeviceExtension->DeviceObject = DeviceObject;
2605
2606 //
2607 // Register the RAM disk device interface
2608 //
2609 Status = IoRegisterDeviceInterface(PhysicalDeviceObject,
2610 &RamdiskBusInterface,
2611 NULL,
2612 &DeviceExtension->BusDeviceName);
2613 if (!NT_SUCCESS(Status))
2614 {
2615 //
2616 // Fail
2617 //
2618 IoDeleteDevice(DeviceObject);
2619 return Status;
2620 }
2621
2622 //
2623 // Attach us to the device stack
2624 //
2625 AttachedDevice = IoAttachDeviceToDeviceStack(DeviceObject,
2626 PhysicalDeviceObject);
2627 DeviceExtension->AttachedDevice = AttachedDevice;
2628 if (!AttachedDevice)
2629 {
2630 //
2631 // Fail
2632 //
2633 IoSetDeviceInterfaceState(&DeviceExtension->BusDeviceName, 0);
2634 RtlFreeUnicodeString(&DeviceExtension->BusDeviceName);
2635 IoDeleteDevice(DeviceObject);
2636 return STATUS_NO_SUCH_DEVICE;
2637 }
2638
2639 //
2640 // Bus FDO is initialized
2641 //
2642 RamdiskBusFdo = DeviceObject;
2643
2644 //
2645 // Loop for loader block
2646 //
2647 if (KeLoaderBlock)
2648 {
2649 //
2650 // Are we being booted from setup? Not yet supported
2651 //
2652 //ASSERT(!KeLoaderBlock->SetupLdrBlock);
2653 }
2654
2655 //
2656 // All done
2657 //
2658 DeviceObject->Flags &= DO_DEVICE_INITIALIZING;
2659 Status = STATUS_SUCCESS;
2660 }
2661
2662 //
2663 // Return status
2664 //
2665 return Status;
2666 }
2667
2668 NTSTATUS
2669 NTAPI
2670 DriverEntry(IN PDRIVER_OBJECT DriverObject,
2671 IN PUNICODE_STRING RegistryPath)
2672 {
2673 PCHAR BootDeviceName, CommandLine;
2674 PDEVICE_OBJECT PhysicalDeviceObject = NULL;
2675 NTSTATUS Status;
2676 DPRINT("RAM Disk Driver Initialized\n");
2677
2678 //
2679 // Query ramdisk parameters
2680 //
2681 QueryParameters(RegistryPath);
2682
2683 //
2684 // Save the registry path
2685 //
2686 DriverRegistryPath = *RegistryPath;
2687 DriverRegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool,
2688 RegistryPath->Length +
2689 sizeof(WCHAR),
2690 'dmaR');
2691 if (!DriverRegistryPath.Buffer) return STATUS_INSUFFICIENT_RESOURCES;
2692 RtlCopyUnicodeString(&DriverRegistryPath, RegistryPath);
2693
2694 //
2695 // Set device routines
2696 //
2697 DriverObject->MajorFunction[IRP_MJ_CREATE] = RamdiskOpenClose;
2698 DriverObject->MajorFunction[IRP_MJ_CLOSE] = RamdiskOpenClose;
2699 DriverObject->MajorFunction[IRP_MJ_READ] = RamdiskReadWrite;
2700 DriverObject->MajorFunction[IRP_MJ_WRITE] = RamdiskReadWrite;
2701 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = RamdiskDeviceControl;
2702 DriverObject->MajorFunction[IRP_MJ_PNP] = RamdiskPnp;
2703 DriverObject->MajorFunction[IRP_MJ_POWER] = RamdiskPower;
2704 DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = RamdiskSystemControl;
2705 DriverObject->MajorFunction[IRP_MJ_SCSI] = RamdiskScsi;
2706 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = RamdiskFlushBuffers;
2707 DriverObject->DriverExtension->AddDevice = RamdiskAddDevice;
2708 DriverObject->DriverUnload = RamdiskUnload;
2709
2710 //
2711 // Check for a loader block
2712 //
2713 if (KeLoaderBlock)
2714 {
2715 //
2716 // Get the boot device name
2717 //
2718 BootDeviceName = KeLoaderBlock->ArcBootDeviceName;
2719 if (BootDeviceName)
2720 {
2721 //
2722 // Check if we're booting from ramdisk
2723 //
2724 if ((strlen(BootDeviceName) >= 10) &&
2725 !(_strnicmp(BootDeviceName, "ramdisk(0)", 10)))
2726 {
2727 //
2728 // We'll have to tell the PnP Manager
2729 //
2730 ReportDetectedDevice = TRUE;
2731
2732 //
2733 // Check for a command line
2734 //
2735 CommandLine = KeLoaderBlock->LoadOptions;
2736 if (CommandLine)
2737 {
2738 //
2739 // Check if this is an ISO boot
2740 //
2741 if (strstr(CommandLine, "RDEXPORTASCD"))
2742 {
2743 //
2744 // Remember for later
2745 //
2746 ExportBootDiskAsCd = TRUE;
2747 }
2748
2749 //
2750 // Check if this is PE boot
2751 //
2752 if (strstr(CommandLine, "MININT"))
2753 {
2754 //
2755 // Remember for later
2756 //
2757 IsWinPEBoot = TRUE;
2758 }
2759 }
2760 }
2761
2762 }
2763 }
2764
2765 //
2766 // Installing from Ramdisk isn't supported yet
2767 //
2768 //ASSERT(!KeLoaderBlock->SetupLdrBlock);
2769
2770 //
2771 // Are we reporting the device
2772 //
2773 if (ReportDetectedDevice)
2774 {
2775 //
2776 // Do it
2777 //
2778 Status = IoReportDetectedDevice(DriverObject,
2779 InterfaceTypeUndefined,
2780 0xFFFFFFFF,
2781 0xFFFFFFFF,
2782 NULL,
2783 NULL,
2784 0,
2785 &PhysicalDeviceObject);
2786 if (NT_SUCCESS(Status))
2787 {
2788 //
2789 // Create the device object
2790 //
2791 Status = RamdiskAddDevice(DriverObject, PhysicalDeviceObject);
2792 if (NT_SUCCESS(Status))
2793 {
2794 //
2795 // We're done
2796 //
2797 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
2798 Status = STATUS_SUCCESS;
2799 }
2800 }
2801 }
2802 else
2803 {
2804 //
2805 // Done
2806 //
2807 Status = STATUS_SUCCESS;
2808 }
2809
2810 //
2811 // Done
2812 //
2813 return Status;
2814 }