/* * PROJECT: Ramdisk Class Driver * LICENSE: BSD - See COPYING.ARM in the top level directory * FILE: drivers/storage/class/ramdisk/ramdisk.c * PURPOSE: Main Driver Routines * PROGRAMMERS: ReactOS Portable Systems Group */ /* INCLUDES *******************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../../filesystems/fs_rec/fs_rec.h" #include #define NDEBUG #include #define DO_XIP 0x00020000 /* GLOBALS ********************************************************************/ #define RAMDISK_SESSION_SIZE \ FIELD_OFFSET(CDROM_TOC, TrackData) + sizeof(TRACK_DATA) #define RAMDISK_TOC_SIZE \ FIELD_OFFSET(CDROM_TOC, TrackData) + 2 * sizeof(TRACK_DATA) #define TOC_DATA_TRACK (0x04) typedef enum _RAMDISK_DEVICE_TYPE { RamdiskBus, RamdiskDrive } RAMDISK_DEVICE_TYPE; typedef enum _RAMDISK_DEVICE_STATE { RamdiskStateUninitialized, RamdiskStateStarted, RamdiskStatePaused, RamdiskStateStopped, RamdiskStateRemoved, RamdiskStateBusRemoved, RamdiskStateEnumerated, } RAMDISK_DEVICE_STATE; DEFINE_GUID(RamdiskBusInterface, 0x5DC52DF0, 0x2F8A, 0x410F, 0x80, 0xE4, 0x05, 0xF8, 0x10, 0xE7, 0xA8, 0x8A); typedef struct _RAMDISK_EXTENSION { RAMDISK_DEVICE_TYPE Type; RAMDISK_DEVICE_STATE State; PDEVICE_OBJECT DeviceObject; PDEVICE_OBJECT PhysicalDeviceObject; PDEVICE_OBJECT AttachedDevice; IO_REMOVE_LOCK RemoveLock; UNICODE_STRING DriveDeviceName; UNICODE_STRING BusDeviceName; FAST_MUTEX DiskListLock; LIST_ENTRY DiskList; } RAMDISK_EXTENSION, *PRAMDISK_EXTENSION; typedef struct _RAMDISK_BUS_EXTENSION { RAMDISK_EXTENSION; } RAMDISK_BUS_EXTENSION, *PRAMDISK_BUS_EXTENSION; typedef struct _RAMDISK_DRIVE_EXTENSION { // // Inherited base class // RAMDISK_EXTENSION; // // Data we get from the creator // GUID DiskGuid; UNICODE_STRING GuidString; UNICODE_STRING SymbolicLinkName; ULONG DiskType; RAMDISK_CREATE_OPTIONS DiskOptions; LARGE_INTEGER DiskLength; LONG DiskOffset; WCHAR DriveLetter; ULONG BasePage; // // Data we get from the disk // ULONG BytesPerSector; ULONG SectorsPerTrack; ULONG NumberOfHeads; ULONG Cylinders; ULONG HiddenSectors; } RAMDISK_DRIVE_EXTENSION, *PRAMDISK_DRIVE_EXTENSION; ULONG MaximumViewLength; ULONG MaximumPerDiskViewLength; ULONG ReportDetectedDevice; ULONG MarkRamdisksAsRemovable; ULONG MinimumViewCount; ULONG DefaultViewCount; ULONG MaximumViewCount; ULONG MinimumViewLength; ULONG DefaultViewLength; UNICODE_STRING DriverRegistryPath; BOOLEAN ExportBootDiskAsCd; BOOLEAN IsWinPEBoot; PDEVICE_OBJECT RamdiskBusFdo; /* FUNCTIONS ******************************************************************/ VOID NTAPI QueryParameters(IN PUNICODE_STRING RegistryPath) { ULONG MinView, DefView, MinViewLength, DefViewLength, MaxViewLength; RTL_QUERY_REGISTRY_TABLE QueryTable[10]; // // Set defaults // MaximumViewLength = 0x10000000u; MaximumPerDiskViewLength = 0x10000000u; ReportDetectedDevice = 0; MarkRamdisksAsRemovable = 0; MinimumViewCount = 2; DefaultViewCount = 16; MaximumViewCount = 64; MinimumViewLength = 0x10000u; DefaultViewLength = 0x100000u; // // Setup the query table and query the registry // RtlZeroMemory(QueryTable, sizeof(QueryTable)); QueryTable[0].Flags = 1; QueryTable[0].Name = L"Parameters"; QueryTable[1].Flags = 32; QueryTable[1].Name = L"ReportDetectedDevice"; QueryTable[1].EntryContext = &ReportDetectedDevice; QueryTable[2].Flags = 32; QueryTable[2].Name = L"MarkRamdisksAsRemovable"; QueryTable[2].EntryContext = &MarkRamdisksAsRemovable; QueryTable[3].Flags = 32; QueryTable[3].Name = L"MinimumViewCount"; QueryTable[3].EntryContext = &MinimumViewCount; QueryTable[4].Flags = 32; QueryTable[4].Name = L"DefaultViewCount"; QueryTable[4].EntryContext = &DefaultViewCount; QueryTable[5].Flags = 32; QueryTable[5].Name = L"MaximumViewCount"; QueryTable[5].EntryContext = &MaximumViewCount; QueryTable[6].Flags = 32; QueryTable[6].Name = L"MinimumViewLength"; QueryTable[6].EntryContext = &MinimumViewLength; QueryTable[7].Flags = 32; QueryTable[7].Name = L"DefaultViewLength"; QueryTable[7].EntryContext = &DefaultViewLength; QueryTable[8].Flags = 32; QueryTable[8].Name = L"MaximumViewLength"; QueryTable[8].EntryContext = &MaximumViewLength; QueryTable[9].Flags = 32; QueryTable[9].Name = L"MaximumPerDiskViewLength"; QueryTable[9].EntryContext = &MaximumPerDiskViewLength; RtlQueryRegistryValues(RTL_REGISTRY_OPTIONAL, RegistryPath->Buffer, QueryTable, NULL, NULL); // // Parse minimum view count, cannot be bigger than 256 or smaller than 2 // MinView = MinimumViewCount; if (MinimumViewCount >= 2) { if (MinimumViewCount > 256) MinView = 256; } else { MinView = 2; } MinimumViewCount = MinView; // // Parse default view count, cannot be bigger than 256 or smaller than minimum // DefView = DefaultViewCount; if (DefaultViewCount >= MinView) { if (DefaultViewCount > 256) DefView = 256; } else { DefView = MinView; } DefaultViewCount = DefView; // // Parse maximum view count, cannot be bigger than 256 or smaller than default // if (MaximumViewCount >= DefView) { if (MaximumViewCount > 256) MaximumViewCount = 256; } else { MaximumViewCount = DefView; } // // Parse minimum view length, cannot be bigger than 1GB or smaller than 64KB // MinViewLength = MinimumViewLength; if (MinimumViewLength >= 0x10000) { if (MinimumViewLength > 0x40000000) MinViewLength = 0x40000000u; } else { MinViewLength = 0x10000u; } MinimumViewLength = MinViewLength; // // Parse default view length, cannot be bigger than 1GB or smaller than minimum // DefViewLength = DefaultViewLength; if (DefaultViewLength >= MinViewLength) { if (DefaultViewLength > 0x40000000) DefViewLength = 0x40000000u; } else { DefViewLength = MinViewLength; } DefaultViewLength = DefViewLength; // // Parse maximum view length, cannot be bigger than 1GB or smaller than default // MaxViewLength = MaximumViewLength; if (MaximumViewLength >= DefViewLength) { if (MaximumViewLength > 0x40000000) MaxViewLength = 0x40000000u; } else { MaxViewLength = DefViewLength; } MaximumViewLength = MaxViewLength; // // Parse maximum view length per disk, cannot be smaller than 16MB // if (MaximumPerDiskViewLength >= 0x1000000) { if (MaxViewLength > 0xFFFFFFFF) MaximumPerDiskViewLength = -1; } else { MaximumPerDiskViewLength = 0x1000000u; } } PVOID NTAPI RamdiskMapPages(IN PRAMDISK_DRIVE_EXTENSION DeviceExtension, IN LARGE_INTEGER Offset, IN ULONG Length, OUT PULONG OutputLength) { PHYSICAL_ADDRESS PhysicalAddress; PVOID MappedBase; ULONG PageOffset; SIZE_T ActualLength; LARGE_INTEGER ActualOffset; LARGE_INTEGER ActualPages; // // We only support boot disks for now // ASSERT(DeviceExtension->DiskType == RAMDISK_BOOT_DISK); // // Calculate the actual offset in the drive // ActualOffset.QuadPart = DeviceExtension->DiskOffset + Offset.QuadPart; // // Convert to pages // ActualPages.QuadPart = ActualOffset.QuadPart >> PAGE_SHIFT; // // Now add the base page // ActualPages.QuadPart = DeviceExtension->BasePage + ActualPages.QuadPart; // // Calculate final amount of bytes // PhysicalAddress.QuadPart = ActualPages.QuadPart << PAGE_SHIFT; // // Calculate pages spanned for the mapping // ActualLength = ADDRESS_AND_SIZE_TO_SPAN_PAGES(ActualOffset.QuadPart, Length); // // And convert this back to bytes // ActualLength <<= PAGE_SHIFT; // // Get the offset within the page // PageOffset = BYTE_OFFSET(ActualOffset.QuadPart); // // Map the I/O Space from the loader // MappedBase = MmMapIoSpace(PhysicalAddress, ActualLength, MmCached); // // Return actual offset within the page as well as the length // if (MappedBase) MappedBase = (PVOID)((ULONG_PTR)MappedBase + PageOffset); *OutputLength = Length; return MappedBase; } VOID NTAPI RamdiskUnmapPages(IN PRAMDISK_DRIVE_EXTENSION DeviceExtension, IN PVOID BaseAddress, IN LARGE_INTEGER Offset, IN ULONG Length) { LARGE_INTEGER ActualOffset; SIZE_T ActualLength; ULONG PageOffset; // // We only support boot disks for now // ASSERT(DeviceExtension->DiskType == RAMDISK_BOOT_DISK); // // Calculate the actual offset in the drive // ActualOffset.QuadPart = DeviceExtension->DiskOffset + Offset.QuadPart; // // Calculate pages spanned for the mapping // ActualLength = ADDRESS_AND_SIZE_TO_SPAN_PAGES(ActualOffset.QuadPart, Length); // // And convert this back to bytes // ActualLength <<= PAGE_SHIFT; // // Get the offset within the page // PageOffset = BYTE_OFFSET(ActualOffset.QuadPart); // // Calculate actual base address where we mapped this // BaseAddress = (PVOID)((ULONG_PTR)BaseAddress - PageOffset); // // Unmap the I/O space we got from the loader // MmUnmapIoSpace(BaseAddress, ActualLength); } NTSTATUS NTAPI RamdiskCreateDiskDevice(IN PRAMDISK_BUS_EXTENSION DeviceExtension, IN PRAMDISK_CREATE_INPUT Input, IN BOOLEAN ValidateOnly, OUT PRAMDISK_DRIVE_EXTENSION *NewDriveExtension) { ULONG BasePage, ViewCount, DiskType, Length; NTSTATUS Status; PDEVICE_OBJECT DeviceObject; PRAMDISK_DRIVE_EXTENSION DriveExtension; PVOID Buffer; WCHAR LocalBuffer[16]; UNICODE_STRING SymbolicLinkName, DriveString, GuidString, DeviceName; PPACKED_BOOT_SECTOR BootSector; BIOS_PARAMETER_BLOCK BiosBlock; ULONG BytesPerSector, SectorsPerTrack, Heads, BytesRead; PVOID BaseAddress; LARGE_INTEGER CurrentOffset, CylinderSize, DiskLength; ULONG CylinderCount, SizeByCylinders; // // Check if we're a boot RAM disk // DiskType = Input->DiskType; if (DiskType >= RAMDISK_BOOT_DISK) { // // Check if we're an ISO // if (DiskType == RAMDISK_BOOT_DISK) { // // NTLDR mounted us somewhere // BasePage = Input->BasePage; if (!BasePage) return STATUS_INVALID_PARAMETER; // // Sanitize disk options // Input->Options.Fixed = TRUE; Input->Options.Readonly = Input->Options.ExportAsCd | Input->Options.Readonly; Input->Options.Hidden = FALSE; Input->Options.NoDosDevice = FALSE; Input->Options.NoDriveLetter = IsWinPEBoot ? TRUE : FALSE; } else { // // The only other possibility is a WIM disk // if (DiskType != RAMDISK_WIM_DISK) { // // Fail // return STATUS_INVALID_PARAMETER; } // // Read the view count instead // ViewCount = Input->ViewCount; // // Sanitize disk options // Input->Options.Hidden = FALSE; Input->Options.NoDosDevice = FALSE; Input->Options.Readonly = FALSE; Input->Options.NoDriveLetter = TRUE; Input->Options.Fixed = TRUE; } // // Are we just validating and returning to the user? // if (ValidateOnly) return STATUS_SUCCESS; // // Build the GUID string // Status = RtlStringFromGUID(&Input->DiskGuid, &GuidString); if (!(NT_SUCCESS(Status)) || !(GuidString.Buffer)) { // // Fail // Status = STATUS_INSUFFICIENT_RESOURCES; goto FailCreate; } // // Allocate our device name // Length = GuidString.Length + 32; Buffer = ExAllocatePoolWithTag(NonPagedPool, Length, 'dmaR'); if (!Buffer) { // // Fail // Status = STATUS_INSUFFICIENT_RESOURCES; goto FailCreate; } // // Build the device name string // DeviceName.Buffer = Buffer; DeviceName.Length = Length - 2; DeviceName.MaximumLength = Length; wcsncpy(Buffer, L"\\Device\\Ramdisk", Length / sizeof(WCHAR)); wcsncat(Buffer, GuidString.Buffer, Length / sizeof(WCHAR)); // // Create the drive device // Status = IoCreateDevice(DeviceExtension->DeviceObject->DriverObject, sizeof(RAMDISK_DRIVE_EXTENSION), &DeviceName, (Input->Options.ExportAsCd) ? FILE_DEVICE_CD_ROM : FILE_DEVICE_DISK, 0, 0, &DeviceObject); if (!NT_SUCCESS(Status)) goto FailCreate; // // Grab the drive extension // DriveExtension = DeviceObject->DeviceExtension; // // Check if we need a DOS device // if (!Input->Options.NoDosDevice) { // // Build the symbolic link name // SymbolicLinkName.MaximumLength = GuidString.Length + 36; SymbolicLinkName.Length = GuidString.Length + 34; Buffer = ExAllocatePoolWithTag(NonPagedPool, SymbolicLinkName.MaximumLength, 'dmaR'); SymbolicLinkName.Buffer = Buffer; if (Buffer) { // // Create it // wcsncpy(Buffer, L"\\GLOBAL??\\Ramdisk", SymbolicLinkName.MaximumLength / sizeof(WCHAR)); wcsncat(Buffer, GuidString.Buffer, SymbolicLinkName.MaximumLength / sizeof(WCHAR)); Status = IoCreateSymbolicLink(&SymbolicLinkName, &DeviceName); if (!NT_SUCCESS(Status)) { // // Nevermind... // Input->Options.NoDosDevice = TRUE; ExFreePool(Buffer); SymbolicLinkName.Buffer = NULL; } } else { // // No DOS device // Input->Options.NoDosDevice = TRUE; } // // It this an ISO boot ramdisk? // if (Input->DiskType == RAMDISK_BOOT_DISK) { // // Does it need a drive letter? // if (!Input->Options.NoDriveLetter) { // // Build it and take over the existing symbolic link // _snwprintf(LocalBuffer, 30, L"\\DosDevices\\%wc:", Input->DriveLetter); RtlInitUnicodeString(&DriveString, LocalBuffer); IoDeleteSymbolicLink(&DriveString); IoCreateSymbolicLink(&DriveString, &DeviceName); // // Save the drive letter // DriveExtension->DriveLetter = Input->DriveLetter; } } } // // Setup the device object flags // DeviceObject->Flags |= (DO_XIP | DO_POWER_PAGABLE | DO_DIRECT_IO); DeviceObject->AlignmentRequirement = 1; // // Build the drive FDO // *NewDriveExtension = DriveExtension; DriveExtension->Type = RamdiskDrive; DiskLength = Input->DiskLength; ExInitializeFastMutex(&DriveExtension->DiskListLock); IoInitializeRemoveLock(&DriveExtension->RemoveLock, 'dmaR', 0, 1); DriveExtension->DriveDeviceName = DeviceName; DriveExtension->SymbolicLinkName = SymbolicLinkName; DriveExtension->GuidString = GuidString; DriveExtension->DiskGuid = Input->DiskGuid; DriveExtension->PhysicalDeviceObject = DeviceObject; DriveExtension->DeviceObject = RamdiskBusFdo; DriveExtension->AttachedDevice = RamdiskBusFdo; DriveExtension->DiskType = Input->DiskType; DriveExtension->DiskOptions = Input->Options; DriveExtension->DiskLength = DiskLength; DriveExtension->DiskOffset = Input->DiskOffset; DriveExtension->BasePage = Input->BasePage; DriveExtension->BytesPerSector = 0; DriveExtension->SectorsPerTrack = 0; DriveExtension->NumberOfHeads = 0; // // Make sure we don't free it later // DeviceName.Buffer = NULL; SymbolicLinkName.Buffer = NULL; GuidString.Buffer = NULL; // // Check if this is an boot disk, or a registry ram drive // if (!(Input->Options.ExportAsCd) && (Input->DiskType == RAMDISK_BOOT_DISK)) { // // Not an ISO boot, but it's a boot FS -- map it to figure out the // drive settings // CurrentOffset.QuadPart = 0; BaseAddress = RamdiskMapPages(DriveExtension, CurrentOffset, PAGE_SIZE, &BytesRead); if (BaseAddress) { // // Get the data // BootSector = (PPACKED_BOOT_SECTOR)BaseAddress; FatUnpackBios(&BiosBlock, &BootSector->PackedBpb); BytesPerSector = BiosBlock.BytesPerSector; SectorsPerTrack = BiosBlock.SectorsPerTrack; Heads = BiosBlock.Heads; // // Save it // DriveExtension->BytesPerSector = BytesPerSector; DriveExtension->SectorsPerTrack = SectorsPerTrack; DriveExtension->NumberOfHeads = Heads; // // Unmap now // CurrentOffset.QuadPart = 0; RamdiskUnmapPages(DriveExtension, BaseAddress, CurrentOffset, BytesRead); } else { // // Fail // Status = STATUS_INSUFFICIENT_RESOURCES; goto FailCreate; } } // // Check if the drive settings haven't been set yet // if ((DriveExtension->BytesPerSector == 0) || (DriveExtension->SectorsPerTrack == 0) || (DriveExtension->NumberOfHeads == 0)) { // // Check if this is a CD // if (Input->Options.ExportAsCd) { // // Setup partition parameters default for ISO 9660 // DriveExtension->BytesPerSector = 2048; DriveExtension->SectorsPerTrack = 32; DriveExtension->NumberOfHeads = 64; } else { // // Setup partition parameters default for FAT // DriveExtension->BytesPerSector = 512; DriveExtension->SectorsPerTrack = 128; DriveExtension->NumberOfHeads = 16; } } // // Calculate the cylinder size // CylinderSize.QuadPart = DriveExtension->BytesPerSector * DriveExtension->SectorsPerTrack * DriveExtension->NumberOfHeads; CylinderCount = DiskLength.QuadPart / CylinderSize.QuadPart; SizeByCylinders = CylinderSize.QuadPart * CylinderCount; DriveExtension->Cylinders = CylinderCount; if ((DiskLength.HighPart > 0) || (SizeByCylinders < DiskLength.LowPart)) { // // Align cylinder size up // DriveExtension->Cylinders++; } // // Acquire the disk lock // KeEnterCriticalRegion(); ExAcquireFastMutex(&DeviceExtension->DiskListLock); // // Insert us // InsertTailList(&DeviceExtension->DiskList, &DriveExtension->DiskList); // // Release the lock // ExReleaseFastMutex(&DeviceExtension->DiskListLock); KeLeaveCriticalRegion(); // // Clear init flag // DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; return STATUS_SUCCESS; } FailCreate: UNIMPLEMENTED; while (TRUE); return STATUS_SUCCESS; } NTSTATUS NTAPI RamdiskCreateRamdisk(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN BOOLEAN ValidateOnly) { PRAMDISK_CREATE_INPUT Input; ULONG Length; PRAMDISK_BUS_EXTENSION DeviceExtension; PRAMDISK_DRIVE_EXTENSION DriveExtension; ULONG DiskType; PWCHAR FileNameStart, FileNameEnd; NTSTATUS Status; PIO_STACK_LOCATION IoStackLocation = IoGetCurrentIrpStackLocation(Irp); // // Get the device extension and our input data // DeviceExtension = DeviceObject->DeviceExtension; Length = IoStackLocation->Parameters.DeviceIoControl.InputBufferLength; Input = (PRAMDISK_CREATE_INPUT)Irp->AssociatedIrp.SystemBuffer; // // Validate input parameters // if ((Length < sizeof(RAMDISK_CREATE_INPUT)) || (Input->Version != sizeof(RAMDISK_CREATE_INPUT))) { // // Invalid input // return STATUS_INVALID_PARAMETER; } // // Validate the disk type // DiskType = Input->DiskType; if (DiskType == RAMDISK_WIM_DISK) return STATUS_INVALID_PARAMETER; // // Look at the disk type // if (DiskType == RAMDISK_BOOT_DISK) { // // We only allow this as an early-init boot // if (!KeLoaderBlock) return STATUS_INVALID_PARAMETER; // // Save command-line flags // if (ExportBootDiskAsCd) Input->Options.ExportAsCd = TRUE; if (IsWinPEBoot) Input->Options.NoDriveLetter = TRUE; } // // Validate the disk type // if ((Input->Options.ExportAsCd) && (DiskType != RAMDISK_BOOT_DISK)) { // // If the type isn't CDFS, it has to at least be raw CD // if (DiskType != RAMDISK_MEMORY_MAPPED_DISK) return STATUS_INVALID_PARAMETER; } // // Check if this is an actual file // if (DiskType <= RAMDISK_MEMORY_MAPPED_DISK) { // // Validate the file name // FileNameStart = (PWCHAR)((ULONG_PTR)Input + Length); FileNameEnd = Input->FileName + 1; while ((FileNameEnd < FileNameStart) && *(FileNameEnd)) FileNameEnd++; if (FileNameEnd == FileNameStart) return STATUS_INVALID_PARAMETER; } // // Create the actual device // Status = RamdiskCreateDiskDevice(DeviceExtension, Input, ValidateOnly, &DriveExtension); if (NT_SUCCESS(Status)) { // // Invalidate and set success // IoInvalidateDeviceRelations(DeviceExtension->PhysicalDeviceObject, 0); Irp->IoStatus.Information = STATUS_SUCCESS; } // // We're done // return Status; } VOID NTAPI RamdiskWorkerThread(IN PDEVICE_OBJECT DeviceObject, IN PVOID Context) { PRAMDISK_BUS_EXTENSION DeviceExtension; NTSTATUS Status; PIO_STACK_LOCATION IoStackLocation; PIRP Irp = Context; // // Get the stack location // IoStackLocation = IoGetCurrentIrpStackLocation(Irp); // // Free the work item // IoFreeWorkItem(Irp->Tail.Overlay.DriverContext[0]); // // Grab the device extension and lock it // DeviceExtension = DeviceObject->DeviceExtension; Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Irp); if (NT_SUCCESS(Status)) { // // Discriminate by major code // switch (IoStackLocation->MajorFunction) { // // Device control // case IRP_MJ_DEVICE_CONTROL: // // Let's take a look at the IOCTL // switch (IoStackLocation->Parameters.DeviceIoControl.IoControlCode) { // // Ramdisk create request // case FSCTL_CREATE_RAM_DISK: // // This time we'll do it for real // Status = RamdiskCreateRamdisk(DeviceObject, Irp, FALSE); break; case IOCTL_DISK_SET_PARTITION_INFO: DPRINT1("Set partition info request\n"); UNIMPLEMENTED; while (TRUE); break; case IOCTL_DISK_GET_DRIVE_LAYOUT: DPRINT1("Get drive layout request\n"); UNIMPLEMENTED; while (TRUE); break; case IOCTL_DISK_GET_PARTITION_INFO: DPRINT1("Get partitinon info request\n"); UNIMPLEMENTED; while (TRUE); break; default: DPRINT1("Invalid request\n"); UNIMPLEMENTED; while (TRUE); break; } // // We're here // break; // // Read or write request // case IRP_MJ_READ: case IRP_MJ_WRITE: DPRINT1("Read/Write request\n"); UNIMPLEMENTED; while (TRUE); break; // // Internal request (SCSI?) // case IRP_MJ_INTERNAL_DEVICE_CONTROL: DPRINT1("SCSI request\n"); UNIMPLEMENTED; while (TRUE); break; // // Flush request // case IRP_MJ_FLUSH_BUFFERS: DPRINT1("Flush request\n"); UNIMPLEMENTED; while (TRUE); break; // // Anything else // default: DPRINT1("Invalid request: %lx\n", IoStackLocation->MajorFunction); UNIMPLEMENTED; while (TRUE); break; } // // Complete the I/O // IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp); Irp->IoStatus.Status = Status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_DISK_INCREMENT); return; } // // Fail the I/O // Irp->IoStatus.Status = Status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); } NTSTATUS NTAPI SendIrpToThread(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PIO_WORKITEM WorkItem; // // Mark the IRP pending // IoMarkIrpPending(Irp); // // Allocate a work item // WorkItem = IoAllocateWorkItem(DeviceObject); if (WorkItem) { // // Queue it up // Irp->Tail.Overlay.DriverContext[0] = WorkItem; IoQueueWorkItem(WorkItem, RamdiskWorkerThread, DelayedWorkQueue, Irp); return STATUS_PENDING; } else { // // Fail // return STATUS_INSUFFICIENT_RESOURCES; } } NTSTATUS NTAPI RamdiskReadWriteReal(IN PIRP Irp, IN PRAMDISK_DRIVE_EXTENSION DeviceExtension) { PMDL Mdl; PVOID CurrentBase, SystemVa, BaseAddress; PIO_STACK_LOCATION IoStackLocation; LARGE_INTEGER CurrentOffset; ULONG BytesRead, BytesLeft, CopyLength; PVOID Source, Destination; NTSTATUS Status; // // Get the MDL and check if it's mapped // Mdl = Irp->MdlAddress; if (Mdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA | MDL_SOURCE_IS_NONPAGED_POOL)) { // // Use the mapped address // SystemVa = Mdl->MappedSystemVa; } else { // // Map it ourselves // SystemVa = MmMapLockedPagesSpecifyCache(Mdl, 0, MmCached, NULL, 0, NormalPagePriority); } // // Make sure we were able to map it // CurrentBase = SystemVa; if (!SystemVa) return STATUS_INSUFFICIENT_RESOURCES; // // Initialize default // Irp->IoStatus.Information = 0; // // Get the I/O Stack Location and capture the data // IoStackLocation = IoGetCurrentIrpStackLocation(Irp); CurrentOffset = IoStackLocation->Parameters.Read.ByteOffset; BytesLeft = IoStackLocation->Parameters.Read.Length; if (!BytesLeft) return STATUS_INVALID_PARAMETER; // // Do the copy loop // while (TRUE) { // // Map the pages // BaseAddress = RamdiskMapPages(DeviceExtension, CurrentOffset, BytesLeft, &BytesRead); if (!BaseAddress) return STATUS_INSUFFICIENT_RESOURCES; // // Update our lengths // Irp->IoStatus.Information += BytesRead; CopyLength = BytesRead; // // Check if this was a read or write // Status = STATUS_SUCCESS; if (IoStackLocation->MajorFunction == IRP_MJ_READ) { // // Set our copy parameters // Destination = CurrentBase; Source = BaseAddress; goto DoCopy; } else if (IoStackLocation->MajorFunction == IRP_MJ_WRITE) { // // Set our copy parameters // Destination = BaseAddress; Source = CurrentBase; DoCopy: // // Copy the data // RtlCopyMemory(Destination, Source, CopyLength); } else { // // Prepare us for failure // BytesLeft = CopyLength; Status = STATUS_INVALID_PARAMETER; } // // Unmap the pages // RamdiskUnmapPages(DeviceExtension, BaseAddress, CurrentOffset, BytesRead); // // Update offset and bytes left // BytesLeft -= BytesRead; CurrentOffset.QuadPart += BytesRead; CurrentBase = (PVOID)((ULONG_PTR)CurrentBase + BytesRead); // // Check if we're done // if (!BytesLeft) return Status; } } NTSTATUS NTAPI RamdiskGetPartitionInfo(IN PIRP Irp, IN PRAMDISK_DRIVE_EXTENSION DeviceExtension) { NTSTATUS Status; PPARTITION_INFORMATION PartitionInfo; PVOID BaseAddress; LARGE_INTEGER Zero = {{0, 0}}; ULONG Length; PIO_STACK_LOCATION IoStackLocation; // // Validate the length // IoStackLocation = IoGetCurrentIrpStackLocation(Irp); if (IoStackLocation->Parameters.DeviceIoControl. OutputBufferLength < sizeof(PARTITION_INFORMATION)) { // // Invalid length // Status = STATUS_BUFFER_TOO_SMALL; Irp->IoStatus.Status = Status; Irp->IoStatus.Information = 0; return Status; } // // Map the partition table // BaseAddress = RamdiskMapPages(DeviceExtension, Zero, PAGE_SIZE, &Length); if (!BaseAddress) { // // No memory // Status = STATUS_INSUFFICIENT_RESOURCES; Irp->IoStatus.Status = Status; Irp->IoStatus.Information = 0; return Status; } // // Fill out the information // PartitionInfo = Irp->AssociatedIrp.SystemBuffer; PartitionInfo->StartingOffset.QuadPart = DeviceExtension->BytesPerSector; PartitionInfo->PartitionLength.QuadPart = DeviceExtension->BytesPerSector * DeviceExtension->SectorsPerTrack * DeviceExtension->NumberOfHeads * DeviceExtension->Cylinders; PartitionInfo->HiddenSectors = DeviceExtension->HiddenSectors; PartitionInfo->PartitionNumber = 0; PartitionInfo->PartitionType = PARTITION_FAT32; //*((PCHAR)BaseAddress + 450); PartitionInfo->BootIndicator = (DeviceExtension->DiskType == RAMDISK_BOOT_DISK) ? TRUE: FALSE; PartitionInfo->RecognizedPartition = IsRecognizedPartition(PartitionInfo-> PartitionType); PartitionInfo->RewritePartition = FALSE; // // Unmap the partition table // RamdiskUnmapPages(DeviceExtension, BaseAddress, Zero, Length); // // Done // Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION); return STATUS_SUCCESS; } NTSTATUS NTAPI RamdiskOpenClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { // // Complete the IRP // Irp->IoStatus.Information = 1; Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } NTSTATUS NTAPI RamdiskReadWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PRAMDISK_DRIVE_EXTENSION DeviceExtension; ULONG Length; LARGE_INTEGER ByteOffset; PIO_STACK_LOCATION IoStackLocation; NTSTATUS Status, ReturnStatus; // // Get the device extension and make sure this isn't a bus // DeviceExtension = DeviceObject->DeviceExtension; if (DeviceExtension->Type == RamdiskBus) { // // Fail // Status = STATUS_INVALID_DEVICE_REQUEST; goto Complete; } // // Capture parameters // IoStackLocation = IoGetCurrentIrpStackLocation(Irp); Length = IoStackLocation->Parameters.Read.Length; ByteOffset = IoStackLocation->Parameters.Read.ByteOffset; // // FIXME: Validate offset // // // FIXME: Validate sector // // // Validate write // if ((IoStackLocation->MajorFunction == IRP_MJ_WRITE) && (DeviceExtension->DiskOptions.Readonly)) { // // Fail, this is read-only // Status = STATUS_MEDIA_WRITE_PROTECTED; goto Complete; } // // See if we want to do this sync or async // if (DeviceExtension->DiskType > RAMDISK_MEMORY_MAPPED_DISK) { // // Do it sync // Status = RamdiskReadWriteReal(Irp, DeviceExtension); goto Complete; } // // Queue it to the worker // Status = SendIrpToThread(DeviceObject, Irp); ReturnStatus = STATUS_PENDING; // // Check if we're pending or not // if (Status != STATUS_PENDING) { Complete: // // Complete the IRP // Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_DISK_INCREMENT); ReturnStatus = Status; } // // Return to caller // return ReturnStatus; } NTSTATUS NTAPI RamdiskDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { NTSTATUS Status; PIO_STACK_LOCATION IoStackLocation = IoGetCurrentIrpStackLocation(Irp); PRAMDISK_BUS_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; PRAMDISK_DRIVE_EXTENSION DriveExtension = (PVOID)DeviceExtension; ULONG Information; PCDROM_TOC Toc; PDISK_GEOMETRY DiskGeometry; // // Grab the remove lock // Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Irp); if (!NT_SUCCESS(Status)) { // // Fail the IRP // Irp->IoStatus.Information = 0; Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; } // // Setup some defaults // Status = STATUS_INVALID_DEVICE_REQUEST; Information = 0; // // Check if this is an bus device or the drive // if (DeviceExtension->Type == RamdiskBus) { // // Check what the request is // switch (IoStackLocation->Parameters.DeviceIoControl.IoControlCode) { // // Request to create a ramdisk // case FSCTL_CREATE_RAM_DISK: // // Do it // Status = RamdiskCreateRamdisk(DeviceObject, Irp, TRUE); if (!NT_SUCCESS(Status)) goto CompleteRequest; break; default: // // We don't handle anything else yet // ASSERT(FALSE); while (TRUE); } } else { // // Check what the request is // switch (IoStackLocation->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_DISK_CHECK_VERIFY: case IOCTL_STORAGE_CHECK_VERIFY: case IOCTL_STORAGE_CHECK_VERIFY2: case IOCTL_CDROM_CHECK_VERIFY: UNIMPLEMENTED; while (TRUE); break; case IOCTL_STORAGE_GET_MEDIA_TYPES: case IOCTL_DISK_GET_MEDIA_TYPES: case IOCTL_DISK_GET_DRIVE_GEOMETRY: case IOCTL_CDROM_GET_DRIVE_GEOMETRY: // // Validate the length // if (IoStackLocation->Parameters.DeviceIoControl. OutputBufferLength < sizeof(DISK_GEOMETRY)) { // // Invalid length // Status = STATUS_BUFFER_TOO_SMALL; break; } // // Fill it out // DiskGeometry = Irp->AssociatedIrp.SystemBuffer; DiskGeometry->Cylinders.QuadPart = DriveExtension->Cylinders; DiskGeometry->BytesPerSector = DriveExtension->BytesPerSector; DiskGeometry->SectorsPerTrack = DriveExtension->SectorsPerTrack; DiskGeometry->TracksPerCylinder = DriveExtension->NumberOfHeads; DiskGeometry->MediaType = DriveExtension->DiskOptions.Fixed ? FixedMedia : RemovableMedia; // // We're done // Status = STATUS_SUCCESS; Information = sizeof(DISK_GEOMETRY); break; // // Hack to support ReactOS's broken CDFS // case IOCTL_CDROM_GET_LAST_SESSION: // // Validate the length // if (IoStackLocation->Parameters.DeviceIoControl. OutputBufferLength < RAMDISK_SESSION_SIZE) { // // Invalid length // Status = STATUS_BUFFER_TOO_SMALL; break; } // // Fill out the TOC // Toc = Irp->AssociatedIrp.SystemBuffer; Toc->Length[0] = 0; Toc->Length[1] = RAMDISK_SESSION_SIZE - sizeof(Toc->Length); Toc->FirstTrack = 1; Toc->LastTrack = 1; Toc->TrackData[0].Adr = 1; Toc->TrackData[0].Control = TOC_DATA_TRACK; Toc->TrackData[0].TrackNumber = 1; Toc->TrackData[0].Address[0] = Toc->TrackData[0].Address[1] = Toc->TrackData[0].Address[2] = Toc->TrackData[0].Address[3] = 0; // // We're done // Status = STATUS_SUCCESS; Information = RAMDISK_SESSION_SIZE; break; case IOCTL_CDROM_READ_TOC: // // Validate the length // if (IoStackLocation->Parameters.DeviceIoControl. OutputBufferLength < sizeof(CDROM_TOC)) { // // Invalid length // Status = STATUS_BUFFER_TOO_SMALL; break; } // // Clear the TOC // Toc = Irp->AssociatedIrp.SystemBuffer; RtlZeroMemory(Toc, sizeof(CDROM_TOC)); // // Fill it out // Toc->Length[0] = 0; Toc->Length[1] = RAMDISK_TOC_SIZE - sizeof(Toc->Length); Toc->FirstTrack = 1; Toc->LastTrack = 1; Toc->TrackData[0].Adr = 1; Toc->TrackData[0].Control = TOC_DATA_TRACK; Toc->TrackData[0].TrackNumber = 1; // // We're done // Status = STATUS_SUCCESS; Information = RAMDISK_TOC_SIZE; break; case IOCTL_DISK_SET_PARTITION_INFO: UNIMPLEMENTED; while (TRUE); break; case IOCTL_DISK_GET_PARTITION_INFO: // // Validate the length // if (IoStackLocation->Parameters.DeviceIoControl. OutputBufferLength < sizeof(PARTITION_INFORMATION)) { // // Invalid length // Status = STATUS_BUFFER_TOO_SMALL; break; } // // Check if we need to do this sync or async // if (DriveExtension->DiskType > RAMDISK_MEMORY_MAPPED_DISK) { // // Call the helper function // Status = RamdiskGetPartitionInfo(Irp, DriveExtension); } else { // // Do it asynchronously later // goto CallWorker; } // // We're done // Information = Irp->IoStatus.Information; break; case IOCTL_DISK_GET_DRIVE_LAYOUT: UNIMPLEMENTED; while (TRUE); break; case IOCTL_DISK_GET_LENGTH_INFO: UNIMPLEMENTED; while (TRUE); break; case IOCTL_DISK_IS_WRITABLE: UNIMPLEMENTED; while (TRUE); break; case IOCTL_SCSI_MINIPORT: UNIMPLEMENTED; while (TRUE); break; case IOCTL_STORAGE_QUERY_PROPERTY: UNIMPLEMENTED; while (TRUE); break; case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID: UNIMPLEMENTED; while (TRUE); break; case IOCTL_MOUNTDEV_QUERY_STABLE_GUID: UNIMPLEMENTED; while (TRUE); break; case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS: UNIMPLEMENTED; while (TRUE); break; case IOCTL_VOLUME_SET_GPT_ATTRIBUTES: UNIMPLEMENTED; while (TRUE); break; case IOCTL_VOLUME_GET_GPT_ATTRIBUTES: UNIMPLEMENTED; while (TRUE); break; case IOCTL_VOLUME_OFFLINE: UNIMPLEMENTED; while (TRUE); break; default: // // Drive code not emulated // DPRINT1("IOCTL: %lx\n", IoStackLocation->Parameters.DeviceIoControl.IoControlCode); break; } // // If requests drop down here, we just return them complete them // goto CompleteRequest; } // // Queue the request to our worker thread // CallWorker: Status = SendIrpToThread(DeviceObject, Irp); CompleteRequest: // // Release the lock // IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp); if (Status != STATUS_PENDING) { // // Complete the request // Irp->IoStatus.Status = Status; Irp->IoStatus.Information = Information; IoCompleteRequest(Irp, IO_NO_INCREMENT); } // // Return status // return Status; } NTSTATUS NTAPI RamdiskQueryDeviceRelations(IN DEVICE_RELATION_TYPE Type, IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PRAMDISK_BUS_EXTENSION DeviceExtension; PRAMDISK_DRIVE_EXTENSION DriveExtension; PDEVICE_RELATIONS DeviceRelations, OurDeviceRelations; ULONG Count, DiskCount, FinalCount; PLIST_ENTRY ListHead, NextEntry; PDEVICE_OBJECT* DriveDeviceObject; RAMDISK_DEVICE_STATE State; // // Get the device extension and check if this is a drive // DeviceExtension = DeviceObject->DeviceExtension; if (DeviceExtension->Type == RamdiskDrive) { // // FIXME: TODO // UNIMPLEMENTED; while (TRUE); } // // Anything but bus relations, we don't handle // if (Type) goto PassToNext; // // Acquire the disk list lock // KeEnterCriticalRegion(); ExAcquireFastMutex(&DeviceExtension->DiskListLock); // // Did a device already fill relations? // DeviceRelations = (PDEVICE_RELATIONS)Irp->IoStatus.Information; if (DeviceRelations) { // // Use the data // Count = DeviceRelations->Count; } else { // // We're the first // Count = 0; } // // Now loop our drives // DiskCount = 0; ListHead = &DeviceExtension->DiskList; NextEntry = ListHead->Flink; while (NextEntry != ListHead) { // // As long as it wasn't removed, count it in // DriveExtension = CONTAINING_RECORD(NextEntry, RAMDISK_DRIVE_EXTENSION, DiskList); if (DriveExtension->State < RamdiskStateBusRemoved) DiskCount++; // // Move to the next one // NextEntry = NextEntry->Flink; } // // Now we know our final count // FinalCount = Count + DiskCount; // // Allocate the structure // OurDeviceRelations = ExAllocatePoolWithTag(PagedPool, FIELD_OFFSET(DEVICE_RELATIONS, Objects) + FinalCount * sizeof(PDEVICE_OBJECT), 'dmaR'); if (!OurDeviceRelations) { // // Fail // ExReleaseFastMutex(&DeviceExtension->DiskListLock); KeLeaveCriticalRegion(); Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INSUFFICIENT_RESOURCES; } // // Check if we already had some relations // if (Count) { // // Copy them in // RtlCopyMemory(OurDeviceRelations->Objects, DeviceRelations->Objects, Count * sizeof(PDEVICE_OBJECT)); } // // Save the count // OurDeviceRelations->Count = FinalCount; // // Now loop our drives again // ListHead = &DeviceExtension->DiskList; NextEntry = ListHead->Flink; while (NextEntry != ListHead) { // // Go to the end of the list // DriveDeviceObject = &OurDeviceRelations->Objects[Count]; // // Get the drive state // DriveExtension = CONTAINING_RECORD(NextEntry, RAMDISK_DRIVE_EXTENSION, DiskList); State = DriveExtension->State; // // If it was removed or enumerated, we don't touch the device object // if (State >= RamdiskStateBusRemoved) { // // If it was removed, we still have to keep track of this though // if (State == RamdiskStateBusRemoved) { // // Mark it as enumerated now, but don't actually reference it // DriveExtension->State = RamdiskStateEnumerated; } } else { // // First time it's enumerated, reference the device object // ObReferenceObject(DriveExtension->DeviceObject); // // Save the object pointer, and move on // *DriveDeviceObject++ = DriveExtension->DeviceObject; } if (DriveExtension->State < RamdiskStateBusRemoved) DiskCount++; // // Move to the next one // NextEntry = NextEntry->Flink; } // // Release the lock // ExReleaseFastMutex(&DeviceExtension->DiskListLock); KeLeaveCriticalRegion(); // // Cleanup old relations // if (DeviceRelations) ExFreePool(DeviceRelations); // // Complete our IRP // Irp->IoStatus.Information = (ULONG_PTR)OurDeviceRelations; Irp->IoStatus.Status = STATUS_SUCCESS; // // Pass to the next driver // PassToNext: IoCopyCurrentIrpStackLocationToNext(Irp); return IoCallDriver(DeviceExtension->AttachedDevice, Irp); } NTSTATUS NTAPI RamdiskPnp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PIO_STACK_LOCATION IoStackLocation; PRAMDISK_BUS_EXTENSION DeviceExtension; NTSTATUS Status; UCHAR Minor; // // Get the device extension and stack location // DeviceExtension = DeviceObject->DeviceExtension; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); Minor = IoStackLocation->MinorFunction; // // Check if the bus is removed // if (DeviceExtension->State == RamdiskStateBusRemoved) { // // Only remove-device and query-id are allowed // if ((Minor != IRP_MN_REMOVE_DEVICE) || (Minor != IRP_MN_QUERY_ID)) { // // Fail anything else // Status = STATUS_NO_SUCH_DEVICE; Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; } } // // Acquire the remove lock // Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Irp); if (!NT_SUCCESS(Status)) { // // Fail the IRP // Irp->IoStatus.Information = 0; Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; } // // Query the IRP type // switch (Minor) { case IRP_MN_START_DEVICE: DPRINT1("PnP IRP: %lx\n", Minor); while (TRUE); break; case IRP_MN_QUERY_STOP_DEVICE: DPRINT1("PnP IRP: %lx\n", Minor); while (TRUE); break; case IRP_MN_CANCEL_STOP_DEVICE: DPRINT1("PnP IRP: %lx\n", Minor); while (TRUE); break; case IRP_MN_STOP_DEVICE: DPRINT1("PnP IRP: %lx\n", Minor); while (TRUE); break; case IRP_MN_QUERY_REMOVE_DEVICE: DPRINT1("PnP IRP: %lx\n", Minor); while (TRUE); break; case IRP_MN_CANCEL_REMOVE_DEVICE: DPRINT1("PnP IRP: %lx\n", Minor); while (TRUE); break; case IRP_MN_REMOVE_DEVICE: DPRINT1("PnP IRP: %lx\n", Minor); while (TRUE); break; case IRP_MN_SURPRISE_REMOVAL: DPRINT1("PnP IRP: %lx\n", Minor); while (TRUE); break; case IRP_MN_QUERY_ID: // // Are we a drive? // if (DeviceExtension->Type == RamdiskDrive) { DPRINT1("PnP IRP: %lx\n", Minor); while (TRUE); } break; case IRP_MN_QUERY_BUS_INFORMATION: // // Are we a drive? // if (DeviceExtension->Type == RamdiskDrive) { DPRINT1("PnP IRP: %lx\n", Minor); while (TRUE); } break; case IRP_MN_EJECT: DPRINT1("PnP IRP: %lx\n", Minor); while (TRUE); break; case IRP_MN_QUERY_DEVICE_TEXT: // // Are we a drive? // if (DeviceExtension->Type == RamdiskDrive) { DPRINT1("PnP IRP: %lx\n", Minor); while (TRUE); } break; case IRP_MN_QUERY_DEVICE_RELATIONS: // // Call our main routine // Status = RamdiskQueryDeviceRelations(IoStackLocation-> Parameters. QueryDeviceRelations.Type, DeviceObject, Irp); goto ReleaseAndReturn; case IRP_MN_QUERY_CAPABILITIES: // // Are we a drive? // if (DeviceExtension->Type == RamdiskDrive) { DPRINT1("PnP IRP: %lx\n", Minor); while (TRUE); } break; case IRP_MN_QUERY_RESOURCES: case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: // // Complete immediately without touching it // IoCompleteRequest(Irp, IO_NO_INCREMENT); goto ReleaseAndReturn; default: DPRINT1("Illegal IRP: %lx\n", Minor); break; } // // Are we the bus? // if (DeviceExtension->Type == RamdiskBus) { // // Do we have an attached device? // if (DeviceExtension->AttachedDevice) { // // Forward the IRP // IoSkipCurrentIrpStackLocation(Irp); Status = IoCallDriver(DeviceExtension->AttachedDevice, Irp); } } // // Release the lock and return status // ReleaseAndReturn: IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp); return Status; } NTSTATUS NTAPI RamdiskPower(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { UNIMPLEMENTED; while (TRUE); return STATUS_SUCCESS; } NTSTATUS NTAPI RamdiskSystemControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { UNIMPLEMENTED; while (TRUE); return STATUS_SUCCESS; } NTSTATUS NTAPI RamdiskScsi(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { UNIMPLEMENTED; while (TRUE); return STATUS_SUCCESS; } NTSTATUS NTAPI RamdiskFlushBuffers(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { UNIMPLEMENTED; while (TRUE); return STATUS_SUCCESS; } VOID NTAPI RamdiskUnload(IN PDRIVER_OBJECT DriverObject) { UNIMPLEMENTED; while (TRUE); } NTSTATUS NTAPI RamdiskAddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject) { PRAMDISK_BUS_EXTENSION DeviceExtension; PDEVICE_OBJECT AttachedDevice; NTSTATUS Status; UNICODE_STRING DeviceName; PDEVICE_OBJECT DeviceObject; // // Only create the bus FDO once // if (RamdiskBusFdo) return STATUS_DEVICE_ALREADY_ATTACHED; // // Create the bus FDO // RtlInitUnicodeString(&DeviceName, L"\\Device\\Ramdisk"); Status = IoCreateDevice(DriverObject, sizeof(RAMDISK_BUS_EXTENSION), &DeviceName, FILE_DEVICE_BUS_EXTENDER, FILE_DEVICE_SECURE_OPEN, 0, &DeviceObject); if (NT_SUCCESS(Status)) { // // Initialize the bus FDO extension // DeviceExtension = DeviceObject->DeviceExtension; RtlZeroMemory(DeviceObject->DeviceExtension, sizeof(RAMDISK_BUS_EXTENSION)); // // Set bus FDO flags // DeviceObject->Flags |= DO_POWER_PAGABLE | DO_DIRECT_IO; // // Setup the bus FDO extension // DeviceExtension->Type = RamdiskBus; ExInitializeFastMutex(&DeviceExtension->DiskListLock); IoInitializeRemoveLock(&DeviceExtension->RemoveLock, 'dmaR', 0, 1); InitializeListHead(&DeviceExtension->DiskList); DeviceExtension->PhysicalDeviceObject = PhysicalDeviceObject; DeviceExtension->DeviceObject = DeviceObject; // // Register the RAM disk device interface // Status = IoRegisterDeviceInterface(PhysicalDeviceObject, &RamdiskBusInterface, NULL, &DeviceExtension->BusDeviceName); if (!NT_SUCCESS(Status)) { // // Fail // IoDeleteDevice(DeviceObject); return Status; } // // Attach us to the device stack // AttachedDevice = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject); DeviceExtension->AttachedDevice = AttachedDevice; if (!AttachedDevice) { // // Fail // IoSetDeviceInterfaceState(&DeviceExtension->BusDeviceName, 0); RtlFreeUnicodeString(&DeviceExtension->BusDeviceName); IoDeleteDevice(DeviceObject); return STATUS_NO_SUCH_DEVICE; } // // Bus FDO is initialized // RamdiskBusFdo = DeviceObject; // // Loop for loader block // if (KeLoaderBlock) { // // Are we being booted from setup? Not yet supported // //ASSERT(!KeLoaderBlock->SetupLdrBlock); } // // All done // DeviceObject->Flags &= DO_DEVICE_INITIALIZING; Status = STATUS_SUCCESS; } // // Return status // return Status; } NTSTATUS NTAPI DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { PCHAR BootDeviceName, CommandLine; PDEVICE_OBJECT PhysicalDeviceObject = NULL; NTSTATUS Status; DPRINT("RAM Disk Driver Initialized\n"); // // Query ramdisk parameters // QueryParameters(RegistryPath); // // Save the registry path // DriverRegistryPath = *RegistryPath; DriverRegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool, RegistryPath->Length + sizeof(WCHAR), 'dmaR'); if (!DriverRegistryPath.Buffer) return STATUS_INSUFFICIENT_RESOURCES; RtlCopyUnicodeString(&DriverRegistryPath, RegistryPath); // // Set device routines // DriverObject->MajorFunction[IRP_MJ_CREATE] = RamdiskOpenClose; DriverObject->MajorFunction[IRP_MJ_CLOSE] = RamdiskOpenClose; DriverObject->MajorFunction[IRP_MJ_READ] = RamdiskReadWrite; DriverObject->MajorFunction[IRP_MJ_WRITE] = RamdiskReadWrite; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = RamdiskDeviceControl; DriverObject->MajorFunction[IRP_MJ_PNP] = RamdiskPnp; DriverObject->MajorFunction[IRP_MJ_POWER] = RamdiskPower; DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = RamdiskSystemControl; DriverObject->MajorFunction[IRP_MJ_SCSI] = RamdiskScsi; DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = RamdiskFlushBuffers; DriverObject->DriverExtension->AddDevice = RamdiskAddDevice; DriverObject->DriverUnload = RamdiskUnload; // // Check for a loader block // if (KeLoaderBlock) { // // Get the boot device name // BootDeviceName = KeLoaderBlock->ArcBootDeviceName; if (BootDeviceName) { // // Check if we're booting from ramdisk // if ((strlen(BootDeviceName) >= 10) && !(_strnicmp(BootDeviceName, "ramdisk(0)", 10))) { // // We'll have to tell the PnP Manager // ReportDetectedDevice = TRUE; // // Check for a command line // CommandLine = KeLoaderBlock->LoadOptions; if (CommandLine) { // // Check if this is an ISO boot // if (strstr(CommandLine, "RDEXPORTASCD")) { // // Remember for later // ExportBootDiskAsCd = TRUE; } // // Check if this is PE boot // if (strstr(CommandLine, "MININT")) { // // Remember for later // IsWinPEBoot = TRUE; } } } } } // // Installing from Ramdisk isn't supported yet // //ASSERT(!KeLoaderBlock->SetupLdrBlock); // // Are we reporting the device // if (ReportDetectedDevice) { // // Do it // Status = IoReportDetectedDevice(DriverObject, InterfaceTypeUndefined, 0xFFFFFFFF, 0xFFFFFFFF, NULL, NULL, 0, &PhysicalDeviceObject); if (NT_SUCCESS(Status)) { // // Create the device object // Status = RamdiskAddDevice(DriverObject, PhysicalDeviceObject); if (NT_SUCCESS(Status)) { // // We're done // PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; Status = STATUS_SUCCESS; } } } else { // // Done // Status = STATUS_SUCCESS; } // // Done // return Status; }