summaryrefslogtreecommitdiff
path: root/storage/ramdisk/src/ramdisk.c
diff options
context:
space:
mode:
authorDave Wilson <[email protected]>2015-04-29 09:48:49 -0700
committerDave Wilson <[email protected]>2015-04-29 10:47:29 -0700
commitd40232638faaab19de557e70a3ee938da7a35295 (patch)
tree14e61c973745949af186b7940e3a53d25322f5de /storage/ramdisk/src/ramdisk.c
parent02e5b090a6131a7cc1b90f4a9373117c9e3c7088 (diff)
samples update for //build
Diffstat (limited to 'storage/ramdisk/src/ramdisk.c')
-rw-r--r--storage/ramdisk/src/ramdisk.c898
1 files changed, 898 insertions, 0 deletions
diff --git a/storage/ramdisk/src/ramdisk.c b/storage/ramdisk/src/ramdisk.c
new file mode 100644
index 00000000..ce571706
--- /dev/null
+++ b/storage/ramdisk/src/ramdisk.c
@@ -0,0 +1,898 @@
+/*++
+
+Copyright (c) Microsoft Corporation, All Rights Reserved
+
+Module Name:
+
+ Ramdisk.c
+
+Abstract:
+
+ This is the Ramdisk sample driver. This version of the driver has been
+ modified to support the driver frameworks. This driver basically creates
+ a nonpaged pool and exposes that as a storage media. User can
+ find the device in the disk manager and format the media to use
+ as FAT or NTFS volume.
+
+Environment:
+
+ Kernel mode only.
+
+--*/
+
+#include "ramdisk.h"
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT, DriverEntry)
+#pragma alloc_text(PAGE, RamDiskEvtDeviceAdd)
+#pragma alloc_text(PAGE, RamDiskEvtDeviceContextCleanup)
+#pragma alloc_text(PAGE, RamDiskQueryDiskRegParameters)
+#pragma alloc_text(PAGE, RamDiskFormatDisk)
+#endif
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ Installable driver initialization entry point.
+ This entry point is called directly by the I/O system.
+
+Arguments:
+
+ DriverObject - pointer to the driver object
+
+ RegistryPath - pointer to a unicode string representing the path
+ to driver-specific key in the registry
+
+Return Value:
+
+ STATUS_SUCCESS if successful.
+
+--*/
+
+{
+ WDF_DRIVER_CONFIG config;
+
+ KdPrint(("Windows Ramdisk Driver - Driver Framework Edition.\n"));
+
+
+ WDF_DRIVER_CONFIG_INIT( &config, RamDiskEvtDeviceAdd );
+
+ return WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, WDF_NO_HANDLE);
+}
+
+VOID
+RamDiskEvtIoRead(
+ IN WDFQUEUE Queue,
+ IN WDFREQUEST Request,
+ IN size_t Length
+ )
+/*++
+
+Routine Description:
+
+ This event is called when the framework receives IRP_MJ_READ request.
+
+Arguments:
+
+ Queue - Handle to the framework queue object that is associated with the
+ I/O request.
+
+ Request - Handle to a framework request object.
+
+ Length - Length of the data buffer associated with the request.
+ The default property of the queue is to not dispatch
+ zero length read & write requests to the driver and
+ complete is with status success. So we will never get
+ a zero length request.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ PDEVICE_EXTENSION devExt = QueueGetExtension(Queue)->DeviceExtension;
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+ WDF_REQUEST_PARAMETERS Parameters;
+ LARGE_INTEGER ByteOffset;
+ WDFMEMORY hMemory;
+
+ _Analysis_assume_(Length > 0);
+
+ WDF_REQUEST_PARAMETERS_INIT(&Parameters);
+ WdfRequestGetParameters(Request, &Parameters);
+
+ ByteOffset.QuadPart = Parameters.Parameters.Read.DeviceOffset;
+
+ if (RamDiskCheckParameters(devExt, ByteOffset, Length)) {
+
+ Status = WdfRequestRetrieveOutputMemory(Request, &hMemory);
+ if(NT_SUCCESS(Status)){
+
+ Status = WdfMemoryCopyFromBuffer(hMemory, // Destination
+ 0, // Offset into the destination
+ devExt->DiskImage + ByteOffset.LowPart, // source
+ Length);
+ }
+ }
+
+ WdfRequestCompleteWithInformation(Request, Status, (ULONG_PTR)Length);
+}
+
+VOID
+RamDiskEvtIoWrite(
+ IN WDFQUEUE Queue,
+ IN WDFREQUEST Request,
+ IN size_t Length
+ )
+
+/*++
+
+Routine Description:
+
+ This event is invoked when the framework receives IRP_MJ_WRITE request.
+
+Arguments:
+
+ Queue - Handle to the framework queue object that is associated with the
+ I/O request.
+
+ Request - Handle to a framework request object.
+
+ Length - Length of the data buffer associated with the request.
+ The default property of the queue is to not dispatch
+ zero length read & write requests to the driver and
+ complete is with status success. So we will never get
+ a zero length request.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ PDEVICE_EXTENSION devExt = QueueGetExtension(Queue)->DeviceExtension;
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+ WDF_REQUEST_PARAMETERS Parameters;
+ LARGE_INTEGER ByteOffset;
+ WDFMEMORY hMemory;
+
+ _Analysis_assume_(Length > 0);
+
+ WDF_REQUEST_PARAMETERS_INIT(&Parameters);
+ WdfRequestGetParameters(Request, &Parameters);
+
+ ByteOffset.QuadPart = Parameters.Parameters.Write.DeviceOffset;
+
+ if (RamDiskCheckParameters(devExt, ByteOffset, Length)) {
+
+ Status = WdfRequestRetrieveInputMemory(Request, &hMemory);
+ if(NT_SUCCESS(Status)){
+
+ Status = WdfMemoryCopyToBuffer(hMemory, // Source
+ 0, // offset in Source memory where the copy has to start
+ devExt->DiskImage + ByteOffset.LowPart, // destination
+ Length);
+ }
+
+ }
+
+ WdfRequestCompleteWithInformation(Request, Status, (ULONG_PTR)Length);
+}
+
+VOID
+RamDiskEvtIoDeviceControl(
+ IN WDFQUEUE Queue,
+ IN WDFREQUEST Request,
+ IN size_t OutputBufferLength,
+ IN size_t InputBufferLength,
+ IN ULONG IoControlCode
+ )
+/*++
+
+Routine Description:
+
+ This event is called when the framework receives IRP_MJ_DEVICE_CONTROL
+ requests from the system.
+
+Arguments:
+
+ Queue - Handle to the framework queue object that is associated
+ with the I/O request.
+ Request - Handle to a framework request object.
+
+ OutputBufferLength - length of the request's output buffer,
+ if an output buffer is available.
+ InputBufferLength - length of the request's input buffer,
+ if an input buffer is available.
+
+ IoControlCode - the driver-defined or system-defined I/O control code
+ (IOCTL) that is associated with the request.
+
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
+ ULONG_PTR information = 0;
+ size_t bufSize;
+ PDEVICE_EXTENSION devExt = QueueGetExtension(Queue)->DeviceExtension;
+
+ UNREFERENCED_PARAMETER(OutputBufferLength);
+ UNREFERENCED_PARAMETER(InputBufferLength);
+
+ switch (IoControlCode) {
+ case IOCTL_DISK_GET_PARTITION_INFO: {
+
+ PPARTITION_INFORMATION outputBuffer;
+ PBOOT_SECTOR bootSector = (PBOOT_SECTOR) devExt->DiskImage;
+
+ information = sizeof(PARTITION_INFORMATION);
+
+ Status = WdfRequestRetrieveOutputBuffer(Request, sizeof(PARTITION_INFORMATION), &outputBuffer, &bufSize);
+ if(NT_SUCCESS(Status) ) {
+
+ outputBuffer->PartitionType =
+ (bootSector->bsFileSystemType[4] == '6') ? PARTITION_FAT_16 : PARTITION_FAT_12;
+
+ outputBuffer->BootIndicator = FALSE;
+ outputBuffer->RecognizedPartition = TRUE;
+ outputBuffer->RewritePartition = FALSE;
+ outputBuffer->StartingOffset.QuadPart = 0;
+ outputBuffer->PartitionLength.QuadPart = devExt->DiskRegInfo.DiskSize;
+ outputBuffer->HiddenSectors = (ULONG) (1L);
+ outputBuffer->PartitionNumber = (ULONG) (-1L);
+
+ Status = STATUS_SUCCESS;
+ }
+ }
+ break;
+
+ case IOCTL_DISK_GET_DRIVE_GEOMETRY: {
+
+ PDISK_GEOMETRY outputBuffer;
+
+ //
+ // Return the drive geometry for the ram disk. Note that
+ // we return values which were made up to suit the disk size.
+ //
+ information = sizeof(DISK_GEOMETRY);
+
+ Status = WdfRequestRetrieveOutputBuffer(Request, sizeof(DISK_GEOMETRY), &outputBuffer, &bufSize);
+ if(NT_SUCCESS(Status) &&
+ bufSize >= sizeof(DISK_GEOMETRY)) {
+
+ RtlCopyMemory(outputBuffer, &(devExt->DiskGeometry), sizeof(DISK_GEOMETRY));
+ Status = STATUS_SUCCESS;
+ }
+ }
+ break;
+
+ case IOCTL_DISK_CHECK_VERIFY:
+ case IOCTL_DISK_IS_WRITABLE:
+
+ //
+ // Return status success
+ //
+
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ WdfRequestCompleteWithInformation(Request, Status, information);
+}
+
+VOID
+RamDiskEvtDeviceContextCleanup(
+ IN WDFOBJECT Device
+ )
+/*++
+
+Routine Description:
+
+ EvtDeviceContextCleanup event callback cleans up anything done in
+ EvtDeviceAdd, except those things that are automatically cleaned
+ up by the Framework.
+
+ In the case of this sample, everything is automatically handled. In a
+ driver derived from this sample, it's quite likely that this function could
+ be deleted.
+
+Arguments:
+
+ Device - Handle to a framework device object.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ PDEVICE_EXTENSION pDeviceExtension = DeviceGetExtension(Device);
+
+ PAGED_CODE();
+
+ if(pDeviceExtension->DiskImage) {
+ ExFreePool(pDeviceExtension->DiskImage);
+ }
+}
+
+NTSTATUS
+RamDiskEvtDeviceAdd(
+ IN WDFDRIVER Driver,
+ IN PWDFDEVICE_INIT DeviceInit
+ )
+/*++
+Routine Description:
+
+ EvtDeviceAdd is called by the framework in response to AddDevice
+ call from the PnP manager. We create and initialize a device object to
+ represent a new instance of the device.
+
+Arguments:
+
+ Driver - Handle to a framework driver object created in DriverEntry
+
+ DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ WDF_OBJECT_ATTRIBUTES deviceAttributes;
+ NTSTATUS status;
+ WDFDEVICE device;
+ WDF_OBJECT_ATTRIBUTES queueAttributes;
+ WDF_IO_QUEUE_CONFIG ioQueueConfig;
+ PDEVICE_EXTENSION pDeviceExtension;
+ PQUEUE_EXTENSION pQueueContext = NULL;
+ WDFQUEUE queue;
+ DECLARE_CONST_UNICODE_STRING(ntDeviceName, NT_DEVICE_NAME);
+
+ PAGED_CODE();
+
+ UNREFERENCED_PARAMETER(Driver);
+
+ //
+ // Storage drivers have to name their FDOs. Since we are not unique'fying
+ // the device name, we wouldn't be able to install more than one instance
+ // of this ramdisk driver.
+ //
+ status = WdfDeviceInitAssignName(DeviceInit, &ntDeviceName);
+ if (!NT_SUCCESS(status)) {
+ return status;
+ }
+
+ WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_DISK);
+ WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect);
+ WdfDeviceInitSetExclusive(DeviceInit, FALSE);
+
+ //
+ // Since this is a pure software only driver, there is no need to register
+ // any PNP/Power event callbacks. Framework will respond to these
+ // events appropriately.
+ //
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_EXTENSION);
+ deviceAttributes.EvtCleanupCallback = RamDiskEvtDeviceContextCleanup;
+
+ status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device);
+ if (!NT_SUCCESS(status)) {
+ return status;
+ }
+
+ //
+ // Now that the WDF device object has been created, set up any context
+ // that it requires.
+ //
+
+ pDeviceExtension = DeviceGetExtension(device);
+
+ //
+ // Configure a default queue so that requests that are not
+ // configure-fowarded using WdfDeviceConfigureRequestDispatching to goto
+ // other queues get dispatched here.
+ //
+ WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE (
+ &ioQueueConfig,
+ WdfIoQueueDispatchSequential
+ );
+
+ ioQueueConfig.EvtIoDeviceControl = RamDiskEvtIoDeviceControl;
+ ioQueueConfig.EvtIoRead = RamDiskEvtIoRead;
+ ioQueueConfig.EvtIoWrite = RamDiskEvtIoWrite;
+
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&queueAttributes, QUEUE_EXTENSION);
+
+ //
+ // By default, Static Driver Verifier (SDV) displays a warning if it
+ // doesn't find the EvtIoStop callback on a power-managed queue.
+ // The 'assume' below causes SDV to suppress this warning. If the driver
+ // has not explicitly set PowerManaged to WdfFalse, the framework creates
+ // power-managed queues when the device is not a filter driver. Normally
+ // the EvtIoStop is required for power-managed queues, but for this driver
+ // it is not needed b/c the driver doesn't hold on to the requests or
+ // forward them to other drivers. This driver completes the requests
+ // directly in the queue's handlers. If the EvtIoStop callback is not
+ // implemented, the framework waits for all driver-owned requests to be
+ // done before moving in the Dx/sleep states or before removing the
+ // device, which is the correct behavior for this type of driver.
+ // If the requests were taking an indeterminate amount of time to complete,
+ // or if the driver forwarded the requests to a lower driver/another stack,
+ // the queue should have an EvtIoStop/EvtIoResume.
+ //
+ __analysis_assume(ioQueueConfig.EvtIoStop != 0);
+ status = WdfIoQueueCreate( device,
+ &ioQueueConfig,
+ &queueAttributes,
+ &queue );
+ __analysis_assume(ioQueueConfig.EvtIoStop == 0);
+ if (!NT_SUCCESS(status)) {
+ return status;
+ }
+
+ // Context is the Queue handle
+ pQueueContext = QueueGetExtension(queue);
+
+ //
+ // Set the context for our default queue as our device extension.
+ //
+ pQueueContext->DeviceExtension = pDeviceExtension;
+
+#if KMDF_VERSION_MINOR >= 9
+
+ //
+ // Enable forward progress on the queue we just created.
+ // NOTE: If you are planning to use this code without forward progress,
+ // comment out the call to SetForwardProgressOnQueue below.
+ //
+ status = SetForwardProgressOnQueue(queue);
+ if (!NT_SUCCESS(status)) {
+ return status;
+ }
+
+#endif
+
+ //
+ // Now do any RAM-Disk specific initialization
+ //
+ pDeviceExtension->DiskRegInfo.DriveLetter.Buffer =
+ (PWSTR) &pDeviceExtension->DriveLetterBuffer;
+ pDeviceExtension->DiskRegInfo.DriveLetter.MaximumLength =
+ sizeof(pDeviceExtension->DriveLetterBuffer);
+
+ //
+ // Get the disk parameters from the registry
+ //
+ RamDiskQueryDiskRegParameters(
+ WdfDriverGetRegistryPath(WdfDeviceGetDriver(device)),
+ &pDeviceExtension->DiskRegInfo
+ );
+
+ //
+ // Allocate memory for the disk image.
+ //
+ pDeviceExtension->DiskImage = ExAllocatePoolWithTag(
+ NonPagedPool,
+ pDeviceExtension->DiskRegInfo.DiskSize,
+ RAMDISK_TAG
+ );
+
+ if (pDeviceExtension->DiskImage) {
+
+ UNICODE_STRING deviceName;
+ UNICODE_STRING win32Name;
+
+ RamDiskFormatDisk(pDeviceExtension);
+
+ status = STATUS_SUCCESS;
+
+ //
+ // Now try to create a symbolic link for the drive letter.
+ //
+ RtlInitUnicodeString(&win32Name, DOS_DEVICE_NAME);
+ RtlInitUnicodeString(&deviceName, NT_DEVICE_NAME);
+
+ pDeviceExtension->SymbolicLink.Buffer = (PWSTR)
+ &pDeviceExtension->DosDeviceNameBuffer;
+ pDeviceExtension->SymbolicLink.MaximumLength =
+ sizeof(pDeviceExtension->DosDeviceNameBuffer);
+ pDeviceExtension->SymbolicLink.Length = win32Name.Length;
+
+ RtlCopyUnicodeString(&pDeviceExtension->SymbolicLink, &win32Name);
+ RtlAppendUnicodeStringToString(&pDeviceExtension->SymbolicLink,
+ &pDeviceExtension->DiskRegInfo.DriveLetter);
+
+ status = WdfDeviceCreateSymbolicLink(device,
+ &pDeviceExtension->SymbolicLink);
+ }
+
+ return status;
+}
+
+VOID
+RamDiskQueryDiskRegParameters(
+ _In_ PWSTR RegistryPath,
+ _In_ PDISK_INFO DiskRegInfo
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from the DriverEntry to get the debug
+ parameters from the registry. If the registry query fails, then
+ default values are used.
+
+Arguments:
+
+ RegistryPath - Points the service path to get the registry parameters
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ RTL_QUERY_REGISTRY_TABLE rtlQueryRegTbl[5 + 1]; // Need 1 for NULL
+ NTSTATUS Status;
+ DISK_INFO defDiskRegInfo;
+
+ PAGED_CODE();
+
+ ASSERT(RegistryPath != NULL);
+
+ // Set the default values
+
+ defDiskRegInfo.DiskSize = DEFAULT_DISK_SIZE;
+ defDiskRegInfo.RootDirEntries = DEFAULT_ROOT_DIR_ENTRIES;
+ defDiskRegInfo.SectorsPerCluster = DEFAULT_SECTORS_PER_CLUSTER;
+
+ RtlInitUnicodeString(&defDiskRegInfo.DriveLetter, DEFAULT_DRIVE_LETTER);
+
+ RtlZeroMemory(rtlQueryRegTbl, sizeof(rtlQueryRegTbl));
+
+ //
+ // Setup the query table
+ //
+
+ rtlQueryRegTbl[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ rtlQueryRegTbl[0].Name = L"Parameters";
+ rtlQueryRegTbl[0].EntryContext = NULL;
+ rtlQueryRegTbl[0].DefaultType = (ULONG_PTR)NULL;
+ rtlQueryRegTbl[0].DefaultData = NULL;
+ rtlQueryRegTbl[0].DefaultLength = (ULONG_PTR)NULL;
+
+ //
+ // Disk paramters
+ //
+
+ rtlQueryRegTbl[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ rtlQueryRegTbl[1].Name = L"DiskSize";
+ rtlQueryRegTbl[1].EntryContext = &DiskRegInfo->DiskSize;
+ rtlQueryRegTbl[1].DefaultType = REG_DWORD;
+ rtlQueryRegTbl[1].DefaultData = &defDiskRegInfo.DiskSize;
+ rtlQueryRegTbl[1].DefaultLength = sizeof(ULONG);
+
+ rtlQueryRegTbl[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ rtlQueryRegTbl[2].Name = L"RootDirEntries";
+ rtlQueryRegTbl[2].EntryContext = &DiskRegInfo->RootDirEntries;
+ rtlQueryRegTbl[2].DefaultType = REG_DWORD;
+ rtlQueryRegTbl[2].DefaultData = &defDiskRegInfo.RootDirEntries;
+ rtlQueryRegTbl[2].DefaultLength = sizeof(ULONG);
+
+ rtlQueryRegTbl[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ rtlQueryRegTbl[3].Name = L"SectorsPerCluster";
+ rtlQueryRegTbl[3].EntryContext = &DiskRegInfo->SectorsPerCluster;
+ rtlQueryRegTbl[3].DefaultType = REG_DWORD;
+ rtlQueryRegTbl[3].DefaultData = &defDiskRegInfo.SectorsPerCluster;
+ rtlQueryRegTbl[3].DefaultLength = sizeof(ULONG);
+
+ rtlQueryRegTbl[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ rtlQueryRegTbl[4].Name = L"DriveLetter";
+ rtlQueryRegTbl[4].EntryContext = &DiskRegInfo->DriveLetter;
+ rtlQueryRegTbl[4].DefaultType = REG_SZ;
+ rtlQueryRegTbl[4].DefaultData = defDiskRegInfo.DriveLetter.Buffer;
+ rtlQueryRegTbl[4].DefaultLength = 0;
+
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
+ RegistryPath,
+ rtlQueryRegTbl,
+ NULL,
+ NULL
+ );
+
+ if (NT_SUCCESS(Status) == FALSE) {
+
+ DiskRegInfo->DiskSize = defDiskRegInfo.DiskSize;
+ DiskRegInfo->RootDirEntries = defDiskRegInfo.RootDirEntries;
+ DiskRegInfo->SectorsPerCluster = defDiskRegInfo.SectorsPerCluster;
+ RtlCopyUnicodeString(&DiskRegInfo->DriveLetter, &defDiskRegInfo.DriveLetter);
+ }
+
+ KdPrint(("DiskSize = 0x%lx\n", DiskRegInfo->DiskSize));
+ KdPrint(("RootDirEntries = 0x%lx\n", DiskRegInfo->RootDirEntries));
+ KdPrint(("SectorsPerCluster = 0x%lx\n", DiskRegInfo->SectorsPerCluster));
+ KdPrint(("DriveLetter = %wZ\n", &(DiskRegInfo->DriveLetter)));
+
+ return;
+}
+
+NTSTATUS
+RamDiskFormatDisk(
+ IN PDEVICE_EXTENSION devExt
+ )
+
+/*++
+
+Routine Description:
+
+ This routine formats the new disk.
+
+
+Arguments:
+
+ DeviceObject - Supplies a pointer to the device object that represents
+ the device whose capacity is to be read.
+
+Return Value:
+
+ status is returned.
+
+--*/
+{
+
+ PBOOT_SECTOR bootSector = (PBOOT_SECTOR) devExt->DiskImage;
+ PUCHAR firstFatSector;
+ ULONG rootDirEntries;
+ ULONG sectorsPerCluster;
+ USHORT fatType; // Type FAT 12 or 16
+ USHORT fatEntries; // Number of cluster entries in FAT
+ USHORT fatSectorCnt; // Number of sectors for FAT
+ PDIR_ENTRY rootDir; // Pointer to first entry in root dir
+
+ PAGED_CODE();
+ ASSERT(sizeof(BOOT_SECTOR) == 512);
+ ASSERT(devExt->DiskImage != NULL);
+
+ RtlZeroMemory(devExt->DiskImage, devExt->DiskRegInfo.DiskSize);
+
+ devExt->DiskGeometry.BytesPerSector = 512;
+ devExt->DiskGeometry.SectorsPerTrack = 32; // Using Ramdisk value
+ devExt->DiskGeometry.TracksPerCylinder = 2; // Using Ramdisk value
+
+ //
+ // Calculate number of cylinders.
+ //
+
+ devExt->DiskGeometry.Cylinders.QuadPart = devExt->DiskRegInfo.DiskSize / 512 / 32 / 2;
+
+ //
+ // Our media type is RAMDISK_MEDIA_TYPE
+ //
+
+ devExt->DiskGeometry.MediaType = RAMDISK_MEDIA_TYPE;
+
+ KdPrint((
+ "Cylinders: %I64d\n TracksPerCylinder: %lu\n SectorsPerTrack: %lu\n BytesPerSector: %lu\n",
+ devExt->DiskGeometry.Cylinders.QuadPart, devExt->DiskGeometry.TracksPerCylinder,
+ devExt->DiskGeometry.SectorsPerTrack, devExt->DiskGeometry.BytesPerSector
+ ));
+
+ rootDirEntries = devExt->DiskRegInfo.RootDirEntries;
+ sectorsPerCluster = devExt->DiskRegInfo.SectorsPerCluster;
+
+ //
+ // Round Root Directory entries up if necessary
+ //
+
+ if (rootDirEntries & (DIR_ENTRIES_PER_SECTOR - 1)) {
+
+ rootDirEntries =
+ (rootDirEntries + (DIR_ENTRIES_PER_SECTOR - 1)) &
+ ~ (DIR_ENTRIES_PER_SECTOR - 1);
+ }
+
+ KdPrint((
+ "Root dir entries: %lu\n Sectors/cluster: %lu\n",
+ rootDirEntries, sectorsPerCluster
+ ));
+
+ //
+ // We need to have the 0xeb and 0x90 since this is one of the
+ // checks the file system recognizer uses
+ //
+
+ bootSector->bsJump[0] = 0xeb;
+ bootSector->bsJump[1] = 0x3c;
+ bootSector->bsJump[2] = 0x90;
+
+ //
+ // Set OemName to "RajuRam "
+ // NOTE: Fill all 8 characters, eg. sizeof(bootSector->bsOemName);
+ //
+ bootSector->bsOemName[0] = 'R';
+ bootSector->bsOemName[1] = 'a';
+ bootSector->bsOemName[2] = 'j';
+ bootSector->bsOemName[3] = 'u';
+ bootSector->bsOemName[4] = 'R';
+ bootSector->bsOemName[5] = 'a';
+ bootSector->bsOemName[6] = 'm';
+ bootSector->bsOemName[7] = ' ';
+
+ bootSector->bsBytesPerSec = (SHORT)devExt->DiskGeometry.BytesPerSector;
+ bootSector->bsResSectors = 1;
+ bootSector->bsFATs = 1;
+ bootSector->bsRootDirEnts = (USHORT)rootDirEntries;
+
+ bootSector->bsSectors = (USHORT)(devExt->DiskRegInfo.DiskSize /
+ devExt->DiskGeometry.BytesPerSector);
+ bootSector->bsMedia = (UCHAR)devExt->DiskGeometry.MediaType;
+ bootSector->bsSecPerClus = (UCHAR)sectorsPerCluster;
+
+ //
+ // Calculate number of sectors required for FAT
+ //
+
+ fatEntries =
+ (bootSector->bsSectors - bootSector->bsResSectors -
+ bootSector->bsRootDirEnts / DIR_ENTRIES_PER_SECTOR) /
+ bootSector->bsSecPerClus + 2;
+
+ //
+ // Choose between 12 and 16 bit FAT based on number of clusters we
+ // need to map
+ //
+
+ if (fatEntries > 4087) {
+ fatType = 16;
+ fatSectorCnt = (fatEntries * 2 + 511) / 512;
+ fatEntries = fatEntries + fatSectorCnt;
+ fatSectorCnt = (fatEntries * 2 + 511) / 512;
+ }
+ else {
+ fatType = 12;
+ fatSectorCnt = (((fatEntries * 3 + 1) / 2) + 511) / 512;
+ fatEntries = fatEntries + fatSectorCnt;
+ fatSectorCnt = (((fatEntries * 3 + 1) / 2) + 511) / 512;
+ }
+
+ bootSector->bsFATsecs = fatSectorCnt;
+ bootSector->bsSecPerTrack = (USHORT)devExt->DiskGeometry.SectorsPerTrack;
+ bootSector->bsHeads = (USHORT)devExt->DiskGeometry.TracksPerCylinder;
+ bootSector->bsBootSignature = 0x29;
+ bootSector->bsVolumeID = 0x12345678;
+
+ //
+ // Set Label to "RamDisk "
+ // NOTE: Fill all 11 characters, eg. sizeof(bootSector->bsLabel);
+ //
+ bootSector->bsLabel[0] = 'R';
+ bootSector->bsLabel[1] = 'a';
+ bootSector->bsLabel[2] = 'm';
+ bootSector->bsLabel[3] = 'D';
+ bootSector->bsLabel[4] = 'i';
+ bootSector->bsLabel[5] = 's';
+ bootSector->bsLabel[6] = 'k';
+ bootSector->bsLabel[7] = ' ';
+ bootSector->bsLabel[8] = ' ';
+ bootSector->bsLabel[9] = ' ';
+ bootSector->bsLabel[10] = ' ';
+
+ //
+ // Set FileSystemType to "FAT1? "
+ // NOTE: Fill all 8 characters, eg. sizeof(bootSector->bsFileSystemType);
+ //
+ bootSector->bsFileSystemType[0] = 'F';
+ bootSector->bsFileSystemType[1] = 'A';
+ bootSector->bsFileSystemType[2] = 'T';
+ bootSector->bsFileSystemType[3] = '1';
+ bootSector->bsFileSystemType[4] = '?';
+ bootSector->bsFileSystemType[5] = ' ';
+ bootSector->bsFileSystemType[6] = ' ';
+ bootSector->bsFileSystemType[7] = ' ';
+
+ bootSector->bsFileSystemType[4] = ( fatType == 16 ) ? '6' : '2';
+
+ bootSector->bsSig2[0] = 0x55;
+ bootSector->bsSig2[1] = 0xAA;
+
+ //
+ // The FAT is located immediately following the boot sector.
+ //
+
+ firstFatSector = (PUCHAR)(bootSector + 1);
+ firstFatSector[0] = (UCHAR)devExt->DiskGeometry.MediaType;
+ firstFatSector[1] = 0xFF;
+ firstFatSector[2] = 0xFF;
+
+ if (fatType == 16) {
+ firstFatSector[3] = 0xFF;
+ }
+
+ //
+ // The Root Directory follows the FAT
+ //
+ rootDir = (PDIR_ENTRY)(bootSector + 1 + fatSectorCnt);
+
+ //
+ // Set device name to "MS-RAMDR"
+ // NOTE: Fill all 8 characters, eg. sizeof(rootDir->deName);
+ //
+ rootDir->deName[0] = 'M';
+ rootDir->deName[1] = 'S';
+ rootDir->deName[2] = '-';
+ rootDir->deName[3] = 'R';
+ rootDir->deName[4] = 'A';
+ rootDir->deName[5] = 'M';
+ rootDir->deName[6] = 'D';
+ rootDir->deName[7] = 'R';
+
+ //
+ // Set device extension name to "IVE"
+ // NOTE: Fill all 3 characters, eg. sizeof(rootDir->deExtension);
+ //
+ rootDir->deExtension[0] = 'I';
+ rootDir->deExtension[1] = 'V';
+ rootDir->deExtension[2] = 'E';
+
+ rootDir->deAttributes = DIR_ATTR_VOLUME;
+
+ return STATUS_SUCCESS;
+}
+
+BOOLEAN
+RamDiskCheckParameters(
+ IN PDEVICE_EXTENSION devExt,
+ IN LARGE_INTEGER ByteOffset,
+ IN size_t Length
+ )
+
+{
+ //
+ // Check for invalid parameters. It is an error for the starting offset
+ // + length to go past the end of the buffer, or for the length to
+ // not be a proper multiple of the sector size.
+ //
+ // Others are possible, but we don't check them since we trust the
+ // file system.
+ //
+
+ if( devExt->DiskRegInfo.DiskSize < Length ||
+ ByteOffset.QuadPart < 0 || // QuadPart is signed so check for negative values
+ ((ULONGLONG)ByteOffset.QuadPart > (devExt->DiskRegInfo.DiskSize - Length)) ||
+ (Length & (devExt->DiskGeometry.BytesPerSector - 1))) {
+
+ //
+ // Do not give an I/O boost for parameter errors.
+ //
+
+ KdPrint((
+ "Error invalid parameter\n"
+ "ByteOffset: %I64x\n"
+ "Length: %lu\n",
+ ByteOffset.QuadPart,
+ Length
+ ));
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+