#ifndef _RAMDISK_H_
#define _RAMDISK_H_
#pragma warning(disable:4201) // nameless struct/union warning
#include <ntddk.h>
#include <ntdddisk.h>
#pragma warning(default:4201)
#include <wdf.h>
#define NTSTRSAFE_LIB
#include <ntstrsafe.h>
#include "forward_progress.h"
#define NT_DEVICE_NAME L"//Device//Ramdisk"
#define DOS_DEVICE_NAME L"//DosDevices//"
#define RAMDISK_TAG 'DmaR' // "RamD"
#define DOS_DEVNAME_LENGTH (sizeof(DOS_DEVICE_NAME)+sizeof(WCHAR)*10)
#define DRIVE_LETTER_LENGTH (sizeof(WCHAR)*10)
#define DRIVE_LETTER_BUFFER_SIZE 10
#define DOS_DEVNAME_BUFFER_SIZE (sizeof(DOS_DEVICE_NAME) / 2) + 10
#define RAMDISK_MEDIA_TYPE 0xF8
#define DIR_ENTRIES_PER_SECTOR 16
#define DEFAULT_DISK_SIZE (1024*1024) // 1 MB
#define DEFAULT_ROOT_DIR_ENTRIES 512
#define DEFAULT_SECTORS_PER_CLUSTER 2
#define DEFAULT_DRIVE_LETTER L"Z:"
typedef struct _DISK_INFO {
ULONG DiskSize; // Ramdisk size in bytes
ULONG RootDirEntries; // No. of root directory entries
ULONG SectorsPerCluster; // Sectors per cluster
UNICODE_STRING DriveLetter; // Drive letter to be used
} DISK_INFO, *PDISK_INFO;
typedef struct _DEVICE_EXTENSION {
PUCHAR DiskImage; // Pointer to beginning of disk image
DISK_GEOMETRY DiskGeometry; // Drive parameters built by Ramdisk
DISK_INFO DiskRegInfo; // Disk parameters from the registry
UNICODE_STRING SymbolicLink; // Dos symbolic name; Drive letter
WCHAR DriveLetterBuffer[DRIVE_LETTER_BUFFER_SIZE];
WCHAR DosDeviceNameBuffer[DOS_DEVNAME_BUFFER_SIZE];
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_EXTENSION, DeviceGetExtension)
typedef struct _QUEUE_EXTENSION {
PDEVICE_EXTENSION DeviceExtension;
} QUEUE_EXTENSION, *PQUEUE_EXTENSION;
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(QUEUE_EXTENSION, QueueGetExtension)
#pragma pack(1)
typedef struct _BOOT_SECTOR
{
UCHAR bsJump[3]; // x86 jmp instruction, checked by FS
CCHAR bsOemName[8]; // OEM name of formatter
USHORT bsBytesPerSec; // Bytes per Sector
UCHAR bsSecPerClus; // Sectors per Cluster
USHORT bsResSectors; // Reserved Sectors
UCHAR bsFATs; // Number of FATs - we always use 1
USHORT bsRootDirEnts; // Number of Root Dir Entries
USHORT bsSectors; // Number of Sectors
UCHAR bsMedia; // Media type - we use RAMDISK_MEDIA_TYPE
USHORT bsFATsecs; // Number of FAT sectors
USHORT bsSecPerTrack; // Sectors per Track - we use 32
USHORT bsHeads; // Number of Heads - we use 2
ULONG bsHiddenSecs; // Hidden Sectors - we set to 0
ULONG bsHugeSectors; // Number of Sectors if > 32 MB size
UCHAR bsDriveNumber; // Drive Number - not used
UCHAR bsReserved1; // Reserved
UCHAR bsBootSignature; // New Format Boot Signature - 0x29
ULONG bsVolumeID; // VolumeID - set to 0x12345678
CCHAR bsLabel[11]; // Label - set to RamDisk
CCHAR bsFileSystemType[8];// File System Type - FAT12 or FAT16
CCHAR bsReserved2[448]; // Reserved
UCHAR bsSig2[2]; // Originial Boot Signature - 0x55, 0xAA
} BOOT_SECTOR, *PBOOT_SECTOR;
typedef struct _DIR_ENTRY
{
UCHAR deName[8]; // File Name
UCHAR deExtension[3]; // File Extension
UCHAR deAttributes; // File Attributes
UCHAR deReserved; // Reserved
USHORT deTime; // File Time
USHORT deDate; // File Date
USHORT deStartCluster; // First Cluster of file
ULONG deFileSize; // File Length
} DIR_ENTRY, *PDIR_ENTRY;
#pragma pack()
//
// Directory Entry Attributes
//
#define DIR_ATTR_READONLY 0x01
#define DIR_ATTR_HIDDEN 0x02
#define DIR_ATTR_SYSTEM 0x04
#define DIR_ATTR_VOLUME 0x08
#define DIR_ATTR_DIRECTORY 0x10
#define DIR_ATTR_ARCHIVE 0x20
DRIVER_INITIALIZE DriverEntry;
EVT_WDF_DRIVER_DEVICE_ADD RamDiskEvtDeviceAdd;
EVT_WDF_DEVICE_CONTEXT_CLEANUP RamDiskEvtDeviceContextCleanup;
EVT_WDF_IO_QUEUE_IO_READ RamDiskEvtIoRead;
EVT_WDF_IO_QUEUE_IO_WRITE RamDiskEvtIoWrite;
EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL RamDiskEvtIoDeviceControl;
VOID
RamDiskQueryDiskRegParameters(
__in PWSTR RegistryPath,
__in PDISK_INFO DiskRegInfo
);
NTSTATUS
RamDiskFormatDisk(
IN PDEVICE_EXTENSION DeviceExtension
);
BOOLEAN
RamDiskCheckParameters(
IN PDEVICE_EXTENSION devExt,
IN LARGE_INTEGER ByteOffset,
IN size_t Length
);
EVT_WDF_OBJECT_CONTEXT_CLEANUP EvtForwardProgressRequestCleanup;
EVT_WDF_OBJECT_CONTEXT_DESTROY EvtForwardProgressRequestDestroy;
EVT_WDF_IO_WDM_IRP_FOR_FORWARD_PROGRESS EvtIoWdmIrpForForwardProgress;
EVT_WDF_IO_ALLOCATE_RESOURCES_FOR_RESERVED_REQUEST EvtIoAllocateResourcesForReservedRequest;
EVT_WDF_IO_ALLOCATE_REQUEST_RESOURCES EvtIoAllocateResources;
/*++
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"
#include "ntintsafe.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"));
KdPrint(("Built %s %s/n", __DATE__, __TIME__));
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) ) {
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);
status = WdfIoQueueCreate( device,
&ioQueueConfig,
&queueAttributes,
&queue );
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;
//
// 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;
}
//
// 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: %ld/n TracksPerCylinder: %ld/n SectorsPerTrack: %ld/n BytesPerSector: %ld/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: %ld/n Sectors/cluster: %ld/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: %d/n",
ByteOffset.QuadPart,
Length
));
return FALSE;
}
return TRUE;
}