[HEADERS]
[reactos.git] / reactos / drivers / storage / class / ramdisk / ramdisk.c
index 9c04c77..1ebe196 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <initguid.h>
 #include <ntddk.h>
+#include <ntifs.h>
 #include <ntdddisk.h>
 #include <ntddcdrm.h>
 #include <scsi.h>
@@ -17,7 +18,6 @@
 #include <ntddvol.h>
 #include <mountdev.h>
 #include <mountmgr.h>
-#include <helper.h>
 #include <ketypes.h>
 #include <iotypes.h>
 #include <rtlfuncs.h>
@@ -28,6 +28,8 @@
 #define NDEBUG
 #include <debug.h>
 
+#define DO_XIP   0x00020000
+
 /* GLOBALS ********************************************************************/
 
 #define RAMDISK_SESSION_SIZE \
@@ -82,18 +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;
@@ -273,22 +289,111 @@ RamdiskMapPages(IN PRAMDISK_DRIVE_EXTENSION DeviceExtension,
                 IN ULONG Length,
                 OUT PULONG OutputLength)
 {
-    DPRINT1("Mapping %lx bytes at %I64x\n", Length, Offset.QuadPart);
-    UNIMPLEMENTED;
-    while (TRUE);
-    return NULL;
+    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;
 }
 
-PVOID
+VOID
 NTAPI
 RamdiskUnmapPages(IN PRAMDISK_DRIVE_EXTENSION DeviceExtension,
                   IN PVOID BaseAddress,
                   IN LARGE_INTEGER Offset,
                   IN ULONG Length)
 {
-    UNIMPLEMENTED;
-    while (TRUE);
-    return NULL;
+    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
@@ -305,10 +410,12 @@ RamdiskCreateDiskDevice(IN PRAMDISK_BUS_EXTENSION DeviceExtension,
     PVOID Buffer;
     WCHAR LocalBuffer[16];
     UNICODE_STRING SymbolicLinkName, DriveString, GuidString, DeviceName;
-    PPACKED_BIOS_PARAMETER_BLOCK Parameters;
+    PPACKED_BOOT_SECTOR BootSector;
+    BIOS_PARAMETER_BLOCK BiosBlock;
     ULONG BytesPerSector, SectorsPerTrack, Heads, BytesRead;
     PVOID BaseAddress;
-    LARGE_INTEGER CurrentOffset;
+    LARGE_INTEGER CurrentOffset, CylinderSize, DiskLength;
+    ULONG CylinderCount, SizeByCylinders;
        
        //
        // Check if we're a boot RAM disk
@@ -389,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)
         {
             //
@@ -407,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
@@ -439,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)
             {
@@ -452,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))
                 {
@@ -491,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);
                     
@@ -516,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;
@@ -530,9 +633,13 @@ 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
         //
@@ -560,10 +667,11 @@ RamdiskCreateDiskDevice(IN PRAMDISK_BUS_EXTENSION DeviceExtension,
                 //
                 // Get the data
                 //
-                Parameters = (PPACKED_BIOS_PARAMETER_BLOCK)BaseAddress;
-                BytesPerSector = Parameters->BytesPerSector[0];
-                SectorsPerTrack = Parameters->SectorsPerTrack[0];
-                Heads = Parameters->Heads[0];
+                BootSector = (PPACKED_BOOT_SECTOR)BaseAddress;
+                FatUnpackBios(&BiosBlock, &BootSector->PackedBpb);
+                BytesPerSector = BiosBlock.BytesPerSector;
+                SectorsPerTrack = BiosBlock.SectorsPerTrack;
+                Heads = BiosBlock.Heads;
                 
                 //
                 // Save it
@@ -590,7 +698,7 @@ RamdiskCreateDiskDevice(IN PRAMDISK_BUS_EXTENSION DeviceExtension,
                 goto FailCreate;
             }
         }
-        
+                
         //
         // Check if the drive settings haven't been set yet
         //
@@ -620,7 +728,24 @@ RamdiskCreateDiskDevice(IN PRAMDISK_BUS_EXTENSION DeviceExtension,
                 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
         //
@@ -890,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;
     }
     
     //
@@ -898,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
@@ -952,7 +1078,7 @@ RamdiskReadWriteReal(IN PIRP Irp,
     // Get the MDL and check if it's mapped
     //
     Mdl = Irp->MdlAddress;
-    if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
+    if (Mdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA | MDL_SOURCE_IS_NONPAGED_POOL))
     {
         //
         // Use the mapped address
@@ -994,7 +1120,6 @@ RamdiskReadWriteReal(IN PIRP Irp,
     //
     // Do the copy loop
     //
-    DPRINT1("Initiating copy loop for %lx bytes at %p\n", BytesLeft, SystemVa);
     while (TRUE)
     {
         //
@@ -1069,6 +1194,80 @@ DoCopy:
     }
 }
 
+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,
@@ -1181,8 +1380,10 @@ RamdiskDeviceControl(IN PDEVICE_OBJECT DeviceObject,
     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
@@ -1257,8 +1458,35 @@ RamdiskDeviceControl(IN PDEVICE_OBJECT DeviceObject,
             case IOCTL_DISK_GET_DRIVE_GEOMETRY:
             case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
                 
-                UNIMPLEMENTED;
-                while (TRUE);
+                //
+                // 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;
             
             //
@@ -1307,7 +1535,6 @@ RamdiskDeviceControl(IN PDEVICE_OBJECT DeviceObject,
                 //
                 // Validate the length
                 //
-                DPRINT1("Output: %lx\n", IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength);
                 if (IoStackLocation->Parameters.DeviceIoControl.
                     OutputBufferLength < sizeof(CDROM_TOC))
                 {
@@ -1327,7 +1554,6 @@ RamdiskDeviceControl(IN PDEVICE_OBJECT DeviceObject,
                 //
                 // Fill it out
                 //
-                DPRINT1("TOC: %d\n", RAMDISK_TOC_SIZE);
                 Toc->Length[0] = 0;
                 Toc->Length[1] = RAMDISK_TOC_SIZE - sizeof(Toc->Length);
                 Toc->FirstTrack = 1;
@@ -1351,8 +1577,41 @@ RamdiskDeviceControl(IN PDEVICE_OBJECT DeviceObject,
                 
             case IOCTL_DISK_GET_PARTITION_INFO:
                 
-                UNIMPLEMENTED;
-                while (TRUE);
+                //
+                // 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:
@@ -1439,6 +1698,7 @@ RamdiskDeviceControl(IN PDEVICE_OBJECT DeviceObject,
     //
     // Queue the request to our worker thread
     //
+CallWorker:
     Status = SendIrpToThread(DeviceObject, Irp);
     
 CompleteRequest:
@@ -1554,7 +1814,7 @@ RamdiskQueryDeviceRelations(IN DEVICE_RELATION_TYPE Type,
                                                             Objects) +
                                                FinalCount *
                                                sizeof(PDEVICE_OBJECT),
-                                               TAG('R', 'a', 'm', 'd'));
+                                               'dmaR');
     if (!OurDeviceRelations)
     {
         //
@@ -1974,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);
@@ -2027,7 +2287,7 @@ RamdiskAddDevice(IN PDRIVER_OBJECT DriverObject,
                        //
                        // Are we being booted from setup? Not yet supported
                        //
-                       ASSERT (!KeLoaderBlock->SetupLdrBlock);
+                       //ASSERT(!KeLoaderBlock->SetupLdrBlock);
            }
 
                //
@@ -2051,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
@@ -2064,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);
     
@@ -2142,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