[HEADERS]
[reactos.git] / reactos / drivers / storage / class / ramdisk / ramdisk.c
index a58d6ba..1ebe196 100644 (file)
 
 #include <initguid.h>
 #include <ntddk.h>
+#include <ntifs.h>
 #include <ntdddisk.h>
+#include <ntddcdrm.h>
 #include <scsi.h>
 #include <ntddscsi.h>
+#include <ntddvol.h>
 #include <mountdev.h>
 #include <mountmgr.h>
-#include <helper.h>
 #include <ketypes.h>
 #include <iotypes.h>
 #include <rtlfuncs.h>
 #include <arc/arc.h>
 #include <reactos/drivers/ntddrdsk.h>
+#include "../../../filesystems/fs_rec/fs_rec.h"
 #include <stdio.h>
 #define NDEBUG
 #include <debug.h>
 
+#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,
@@ -50,20 +63,19 @@ DEFINE_GUID(RamdiskBusInterface,
                        0x410F,
                        0x80, 0xE4, 0x05, 0xF8, 0x10, 0xE7, 0xA8, 0x8A);
 
-//
-// GCC does not seem to support anonymous structures
-//
-#define 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;                 \
+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
 {
@@ -72,15 +84,32 @@ typedef struct _RAMDISK_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;
-    LONGLONG DiskLength;
+    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;
@@ -253,6 +282,120 @@ QueryParameters(IN PUNICODE_STRING RegistryPath)
     }
 }
 
+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,
@@ -267,17 +410,23 @@ RamdiskCreateDiskDevice(IN PRAMDISK_BUS_EXTENSION DeviceExtension,
     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 CDROM-type RAM disk
+       // Check if we're a boot RAM disk
        //
        DiskType = Input->DiskType;
-       if (DiskType > FILE_DEVICE_CD_ROM)
+       if (DiskType >= RAMDISK_BOOT_DISK)
        {
                //
                // Check if we're an ISO
                // 
-               if (DiskType == FILE_DEVICE_CD_ROM_FILE_SYSTEM)
+               if (DiskType == RAMDISK_BOOT_DISK)
                {
                        //
                        // NTLDR mounted us somewhere
@@ -298,10 +447,15 @@ RamdiskCreateDiskDevice(IN PRAMDISK_BUS_EXTENSION DeviceExtension,
                else
                {
                        //
-                       // The only other possibility is a controller
+                       // The only other possibility is a WIM disk
                        //
-                       if (DiskType != FILE_DEVICE_CONTROLLER)
+                       if (DiskType != RAMDISK_WIM_DISK)
+            {
+                //
+                // Fail
+                //
                 return STATUS_INVALID_PARAMETER;
+            }
                        
                        //
                        // Read the view count instead
@@ -342,7 +496,7 @@ RamdiskCreateDiskDevice(IN PRAMDISK_BUS_EXTENSION DeviceExtension,
         Length = GuidString.Length + 32;
         Buffer = ExAllocatePoolWithTag(NonPagedPool,
                                        Length,
-                                       TAG('R', 'a', 'm', 'd'));
+                                       'dmaR');
         if (!Buffer)
         {
             //
@@ -360,7 +514,6 @@ RamdiskCreateDiskDevice(IN PRAMDISK_BUS_EXTENSION DeviceExtension,
         DeviceName.MaximumLength = Length;
         wcsncpy(Buffer, L"\\Device\\Ramdisk", Length / sizeof(WCHAR));
         wcsncat(Buffer, GuidString.Buffer, Length / sizeof(WCHAR));
-        DPRINT1("Creating device: %wZ\n", &DeviceName);
         
         //
         // Create the drive device
@@ -368,8 +521,9 @@ RamdiskCreateDiskDevice(IN PRAMDISK_BUS_EXTENSION DeviceExtension,
         Status = IoCreateDevice(DeviceExtension->DeviceObject->DriverObject,
                                 sizeof(RAMDISK_DRIVE_EXTENSION),
                                 &DeviceName,
-                                FILE_DEVICE_DISK_FILE_SYSTEM, // FIXME: DISK
-                                FILE_READ_ONLY_DEVICE, // FIXME: Not always
+                                (Input->Options.ExportAsCd) ?
+                                FILE_DEVICE_CD_ROM : FILE_DEVICE_DISK,
+                                0,
                                 0,
                                 &DeviceObject);
         if (!NT_SUCCESS(Status)) goto FailCreate;
@@ -391,7 +545,7 @@ RamdiskCreateDiskDevice(IN PRAMDISK_BUS_EXTENSION DeviceExtension,
             SymbolicLinkName.Length = GuidString.Length + 34;
             Buffer = ExAllocatePoolWithTag(NonPagedPool,
                                            SymbolicLinkName.MaximumLength,
-                                           TAG('R', 'a', 'm', 'd'));
+                                           'dmaR');
             SymbolicLinkName.Buffer = Buffer;
             if (Buffer)
             {
@@ -404,8 +558,6 @@ RamdiskCreateDiskDevice(IN PRAMDISK_BUS_EXTENSION DeviceExtension,
                 wcsncat(Buffer,
                         GuidString.Buffer,
                         SymbolicLinkName.MaximumLength / sizeof(WCHAR));
-                DPRINT1("Creating symbolic link: %wZ to %wZ \n",
-                        &SymbolicLinkName, &DeviceName);
                 Status = IoCreateSymbolicLink(&SymbolicLinkName, &DeviceName);
                 if (!NT_SUCCESS(Status))
                 {
@@ -428,7 +580,7 @@ RamdiskCreateDiskDevice(IN PRAMDISK_BUS_EXTENSION DeviceExtension,
             //
             // It this an ISO boot ramdisk?
             //
-            if (Input->DiskType == FILE_DEVICE_CD_ROM_FILE_SYSTEM)
+            if (Input->DiskType == RAMDISK_BOOT_DISK)
             {
                 //
                 // Does it need a drive letter?
@@ -443,8 +595,6 @@ RamdiskCreateDiskDevice(IN PRAMDISK_BUS_EXTENSION DeviceExtension,
                                L"\\DosDevices\\%wc:",
                                Input->DriveLetter);
                     RtlInitUnicodeString(&DriveString, LocalBuffer);
-                    DPRINT1("Creating symbolic link: %wZ to %wZ\n",
-                            &DriveString, &DeviceName);
                     IoDeleteSymbolicLink(&DriveString);
                     IoCreateSymbolicLink(&DriveString, &DeviceName);
                     
@@ -468,9 +618,10 @@ RamdiskCreateDiskDevice(IN PRAMDISK_BUS_EXTENSION DeviceExtension,
         //
         *NewDriveExtension = DriveExtension;
         DriveExtension->Type = RamdiskDrive;
+        DiskLength = Input->DiskLength;
                ExInitializeFastMutex(&DriveExtension->DiskListLock);
            IoInitializeRemoveLock(&DriveExtension->RemoveLock,
-                               TAG('R', 'a', 'm', 'd'),
+                               'dmaR',
                                0,
                                1);
         DriveExtension->DriveDeviceName = DeviceName;
@@ -482,16 +633,142 @@ RamdiskCreateDiskDevice(IN PRAMDISK_BUS_EXTENSION DeviceExtension,
         DriveExtension->AttachedDevice = RamdiskBusFdo;
         DriveExtension->DiskType = Input->DiskType;
         DriveExtension->DiskOptions = Input->Options;
-        DriveExtension->DiskLength = Input->DiskLength;
+        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;
@@ -537,12 +814,12 @@ RamdiskCreateRamdisk(IN PDEVICE_OBJECT DeviceObject,
        // Validate the disk type
        //
        DiskType = Input->DiskType;
-       if (DiskType == FILE_DEVICE_CONTROLLER) return STATUS_INVALID_PARAMETER;
+       if (DiskType == RAMDISK_WIM_DISK) return STATUS_INVALID_PARAMETER;
        
        //
        // Look at the disk type
        //
-       if (DiskType == FILE_DEVICE_CD_ROM_FILE_SYSTEM)
+       if (DiskType == RAMDISK_BOOT_DISK)
        {
                //
                // We only allow this as an early-init boot
@@ -559,19 +836,18 @@ RamdiskCreateRamdisk(IN PDEVICE_OBJECT DeviceObject,
        //
        // Validate the disk type
        //
-       if ((Input->Options.ExportAsCd) &&
-        (DiskType != FILE_DEVICE_CD_ROM_FILE_SYSTEM))
+       if ((Input->Options.ExportAsCd) && (DiskType != RAMDISK_BOOT_DISK))
        {
                //
                // If the type isn't CDFS, it has to at least be raw CD
                //
-               if (DiskType != FILE_DEVICE_CD_ROM) return STATUS_INVALID_PARAMETER;
+               if (DiskType != RAMDISK_MEMORY_MAPPED_DISK) return STATUS_INVALID_PARAMETER;
        }
        
        //
        // Check if this is an actual file
        //
-       if (DiskType <= FILE_DEVICE_CD_ROM)
+       if (DiskType <= RAMDISK_MEMORY_MAPPED_DISK)
        {
                //
                // Validate the file name
@@ -739,7 +1015,8 @@ RamdiskWorkerThread(IN PDEVICE_OBJECT DeviceObject,
         IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp);
         Irp->IoStatus.Status = Status;
         Irp->IoStatus.Information = 0;
-        return IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+        IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+        return;
     }
     
     //
@@ -747,7 +1024,7 @@ RamdiskWorkerThread(IN PDEVICE_OBJECT DeviceObject,
     //
     Irp->IoStatus.Status = Status;
     Irp->IoStatus.Information = 0;
-    return IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
 }
 
 NTSTATUS
@@ -784,6 +1061,213 @@ SendIrpToThread(IN PDEVICE_OBJECT DeviceObject,
     }
 }
 
+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,
@@ -803,9 +1287,89 @@ NTAPI
 RamdiskReadWrite(IN PDEVICE_OBJECT DeviceObject,
                  IN PIRP Irp)
 {
-    UNIMPLEMENTED;
-    while (TRUE);
-    return STATUS_SUCCESS;
+    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
@@ -816,7 +1380,10 @@ RamdiskDeviceControl(IN PDEVICE_OBJECT DeviceObject,
     NTSTATUS Status;
     PIO_STACK_LOCATION IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
     PRAMDISK_BUS_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
-    ULONG Information = 0;
+    PRAMDISK_DRIVE_EXTENSION DriveExtension = (PVOID)DeviceExtension;
+    ULONG Information;
+    PCDROM_TOC Toc;
+    PDISK_GEOMETRY DiskGeometry;
     
     //
     // Grab the remove lock
@@ -833,6 +1400,12 @@ RamdiskDeviceControl(IN PDEVICE_OBJECT DeviceObject,
         return Status;
     }
     
+    //
+    // Setup some defaults
+    //
+    Status = STATUS_INVALID_DEVICE_REQUEST;
+    Information = 0;
+    
     //
     // Check if this is an bus device or the drive
     //
@@ -867,14 +1440,265 @@ RamdiskDeviceControl(IN PDEVICE_OBJECT DeviceObject,
     else
     {
         //
-        // Drive code not yet done
+        // 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
         //
-        ASSERT(FALSE);
+        goto CompleteRequest;
     }
     
     //
     // Queue the request to our worker thread
     //
+CallWorker:
     Status = SendIrpToThread(DeviceObject, Irp);
     
 CompleteRequest:
@@ -990,7 +1814,7 @@ RamdiskQueryDeviceRelations(IN DEVICE_RELATION_TYPE Type,
                                                             Objects) +
                                                FinalCount *
                                                sizeof(PDEVICE_OBJECT),
-                                               TAG('R', 'a', 'm', 'd'));
+                                               'dmaR');
     if (!OurDeviceRelations)
     {
         //
@@ -1410,7 +2234,7 @@ RamdiskAddDevice(IN PDRIVER_OBJECT DriverObject,
            DeviceExtension->Type = RamdiskBus;
                ExInitializeFastMutex(&DeviceExtension->DiskListLock);
            IoInitializeRemoveLock(&DeviceExtension->RemoveLock,
-                               TAG('R', 'a', 'm', 'd'),
+                               'dmaR',
                                0,
                                1);
                InitializeListHead(&DeviceExtension->DiskList);
@@ -1463,7 +2287,7 @@ RamdiskAddDevice(IN PDRIVER_OBJECT DriverObject,
                        //
                        // Are we being booted from setup? Not yet supported
                        //
-                       ASSERT (!KeLoaderBlock->SetupLdrBlock);
+                       //ASSERT(!KeLoaderBlock->SetupLdrBlock);
            }
 
                //
@@ -1487,6 +2311,7 @@ DriverEntry(IN PDRIVER_OBJECT DriverObject,
     PCHAR BootDeviceName, CommandLine;
     PDEVICE_OBJECT PhysicalDeviceObject = NULL;
     NTSTATUS Status;
+    DPRINT("RAM Disk Driver Initialized\n");
     
     //
     // Query ramdisk parameters
@@ -1500,7 +2325,7 @@ DriverEntry(IN PDRIVER_OBJECT DriverObject,
     DriverRegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool,
                                                       RegistryPath->Length +
                                                       sizeof(WCHAR),
-                                                      TAG('R', 'a', 'm', 'd'));
+                                                      'dmaR');
     if (!DriverRegistryPath.Buffer) return STATUS_INSUFFICIENT_RESOURCES;
     RtlCopyUnicodeString(&DriverRegistryPath, RegistryPath);
     
@@ -1578,7 +2403,7 @@ DriverEntry(IN PDRIVER_OBJECT DriverObject,
     //
     // Installing from Ramdisk isn't supported yet
     //
-    ASSERT(!KeLoaderBlock->SetupLdrBlock);
+    //ASSERT(!KeLoaderBlock->SetupLdrBlock);
     
     //
     // Are we reporting the device