123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724 |
- /*++
- Copyright (c) 2012 Minoca Corp. All Rights Reserved
- Module Name:
- ramdisk.c
- Abstract:
- This module implements driver support for RAM disks. This RAM disk driver
- serves as an excellent simple example for Open, Close, I/O, and system
- control IRPs. It is fairly unusual (and therefore probably not a good
- example) in relation to its DriverEntry, AddDevice, and StateChange
- handling. Be aware of this if using this driver as a template to write
- your own.
- Author:
- Evan Green 17-Oct-2012
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/driver.h>
- #include <minoca/kernel/sysres.h>
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define RAM_DISK_ALLOCATION_TAG 0x444D4152 // 'DMAR'
- #define RAM_DISK_SECTOR_SIZE 0x200
- //
- // --------------------------------------------------------------------- Macros
- //
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- /*++
- Structure Description:
- This structure defines state associated with a RAM disk.
- Members:
- PhysicalAddress - Stores the physical address of the buffer.
- Buffer - Stores a pointer to the buffer of the raw RAM disk.
- Size - Stores the total size of the RAM disk, in bytes.
- --*/
- typedef struct _RAM_DISK_DEVICE {
- PHYSICAL_ADDRESS PhysicalAddress;
- PVOID Buffer;
- ULONGLONG Size;
- } RAM_DISK_DEVICE, *PRAM_DISK_DEVICE;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- KSTATUS
- RamDiskAddDevice (
- PVOID Driver,
- PSTR DeviceId,
- PSTR ClassId,
- PSTR CompatibleIds,
- PVOID DeviceToken
- );
- VOID
- RamDiskDispatchStateChange (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- RamDiskDispatchOpen (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- RamDiskDispatchClose (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- RamDiskDispatchIo (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- RamDiskDispatchSystemControl (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // Store a pointer to the driver object.
- //
- PDRIVER RamDiskDriver = NULL;
- //
- // Store the next identifier.
- //
- volatile ULONG RamDiskNextIdentifier = 0;
- //
- // ------------------------------------------------------------------ Functions
- //
- KSTATUS
- DriverEntry (
- PDRIVER Driver
- )
- /*++
- Routine Description:
- This routine is the entry point for the RAM disk driver. It registers its
- other dispatch functions, and performs driver-wide initialization.
- Arguments:
- Driver - Supplies a pointer to the driver object.
- Return Value:
- STATUS_SUCCESS on success.
- Failure code on error.
- --*/
- {
- volatile ULONG DeviceId;
- CHAR DeviceIdString[11];
- DRIVER_FUNCTION_TABLE FunctionTable;
- PSYSTEM_RESOURCE_HEADER GenericHeader;
- PRAM_DISK_DEVICE RamDiskDevice;
- PSYSTEM_RESOURCE_RAM_DISK RamDiskResource;
- KSTATUS Status;
- RamDiskDriver = Driver;
- RtlZeroMemory(&FunctionTable, sizeof(DRIVER_FUNCTION_TABLE));
- FunctionTable.Version = DRIVER_FUNCTION_TABLE_VERSION;
- FunctionTable.AddDevice = RamDiskAddDevice;
- FunctionTable.DispatchStateChange = RamDiskDispatchStateChange;
- FunctionTable.DispatchOpen = RamDiskDispatchOpen;
- FunctionTable.DispatchClose = RamDiskDispatchClose;
- FunctionTable.DispatchIo = RamDiskDispatchIo;
- FunctionTable.DispatchSystemControl = RamDiskDispatchSystemControl;
- Status = IoRegisterDriverFunctions(Driver, &FunctionTable);
- if (!KSUCCESS(Status)) {
- goto DriverEntryEnd;
- }
- //
- // Get all RAM disks from the boot environment. This is not normally how
- // devices are created or enumerated. The RAM disk is special in that its
- // devices and resources are essentially born out of the boot environment.
- // Don't copy this loop if using this driver as a template.
- //
- while (TRUE) {
- GenericHeader = KeAcquireSystemResource(SystemResourceRamDisk);
- if (GenericHeader == NULL) {
- break;
- }
- RamDiskResource = (PSYSTEM_RESOURCE_RAM_DISK)GenericHeader;
- //
- // Allocate the internal data structure.
- //
- RamDiskDevice = MmAllocateNonPagedPool(sizeof(RAM_DISK_DEVICE),
- RAM_DISK_ALLOCATION_TAG);
- if (RamDiskDevice == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto DriverEntryEnd;
- }
- RtlZeroMemory(RamDiskDevice, sizeof(RAM_DISK_DEVICE));
- RamDiskDevice->PhysicalAddress =
- RamDiskResource->Header.PhysicalAddress;
- RamDiskDevice->Buffer = RamDiskResource->Header.VirtualAddress;
- RamDiskDevice->Size = RamDiskResource->Header.Size;
- DeviceId = RtlAtomicAdd32(&RamDiskNextIdentifier, 1);
- RtlPrintToString(DeviceIdString,
- 11,
- CharacterEncodingDefault,
- "RamDisk%x",
- DeviceId);
- //
- // Create the RAM disk device.
- //
- Status = IoCreateDevice(RamDiskDriver,
- RamDiskDevice,
- NULL,
- DeviceIdString,
- DISK_CLASS_ID,
- NULL,
- NULL);
- if (!KSUCCESS(Status)) {
- goto DriverEntryEnd;
- }
- }
- DriverEntryEnd:
- return Status;
- }
- KSTATUS
- RamDiskAddDevice (
- PVOID Driver,
- PSTR DeviceId,
- PSTR ClassId,
- PSTR CompatibleIds,
- PVOID DeviceToken
- )
- /*++
- Routine Description:
- This routine is called when a RAM disk is detected.
- Arguments:
- Driver - Supplies a pointer to the driver being called.
- DeviceId - Supplies a pointer to a string with the device ID.
- ClassId - Supplies a pointer to a string containing the device's class ID.
- CompatibleIds - Supplies a pointer to a string containing device IDs
- that would be compatible with this device.
- DeviceToken - Supplies an opaque token that the driver can use to identify
- the device in the system. This token should be used when attaching to
- the stack.
- Return Value:
- STATUS_SUCCESS on success.
- Failure code if the driver was unsuccessful in attaching itself.
- --*/
- {
- //
- // The RAM disk is not a real device, so it is not expected to be
- // attaching to emerging stacks. A proper driver should examine the device
- // ID and call IoAttachDriverToDevice to connect their driver to a newly
- // enumerated device.
- //
- return STATUS_NOT_IMPLEMENTED;
- }
- VOID
- RamDiskDispatchStateChange (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles State Change IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- BOOL CompleteIrp;
- KSTATUS Status;
- ASSERT(Irp->MajorCode == IrpMajorStateChange);
- //
- // The IRP is on its way down the stack. Do most processing here.
- //
- if (Irp->Direction == IrpDown) {
- Status = STATUS_NOT_SUPPORTED;
- CompleteIrp = TRUE;
- switch (Irp->MinorCode) {
- case IrpMinorQueryResources:
- Status = STATUS_SUCCESS;
- break;
- case IrpMinorStartDevice:
- Status = STATUS_SUCCESS;
- break;
- case IrpMinorQueryChildren:
- Irp->U.QueryChildren.Children = NULL;
- Irp->U.QueryChildren.ChildCount = 0;
- Status = STATUS_SUCCESS;
- break;
- //
- // Pass all other IRPs down.
- //
- default:
- CompleteIrp = FALSE;
- break;
- }
- //
- // Complete the IRP unless there's a reason not to. Normal drivers
- // should only complete the IRP if they're a bus driver or an error
- // occurred. The RAM disk is special as it created itself (and so it is
- // its own bus driver).
- //
- if (CompleteIrp != FALSE) {
- IoCompleteIrp(RamDiskDriver, Irp, Status);
- }
- //
- // The IRP is completed and is on its way back up. In normal device
- // drivers, this would be where to process the IRP, as by this point the
- // bus driver has performed necessary work (like enabling access to the
- // device on the bus in the case of start IRPs).
- //
- } else {
- ASSERT(Irp->Direction == IrpUp);
- }
- return;
- }
- VOID
- RamDiskDispatchOpen (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles Open IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- PRAM_DISK_DEVICE Disk;
- PRAM_DISK_DEVICE DiskCopy;
- Disk = (PRAM_DISK_DEVICE)DeviceContext;
- DiskCopy = MmAllocatePagedPool(sizeof(RAM_DISK_DEVICE),
- RAM_DISK_ALLOCATION_TAG);
- if (DiskCopy == NULL) {
- IoCompleteIrp(RamDiskDriver, Irp, STATUS_INSUFFICIENT_RESOURCES);
- return;
- }
- RtlCopyMemory(DiskCopy, Disk, sizeof(RAM_DISK_DEVICE));
- Irp->U.Open.DeviceContext = DiskCopy;
- IoCompleteIrp(RamDiskDriver, Irp, STATUS_SUCCESS);
- return;
- }
- VOID
- RamDiskDispatchClose (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles Close IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- MmFreePagedPool(Irp->U.Close.DeviceContext);
- IoCompleteIrp(RamDiskDriver, Irp, STATUS_SUCCESS);
- return;
- }
- VOID
- RamDiskDispatchIo (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles I/O IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- UINTN BytesToComplete;
- KSTATUS CompletionStatus;
- PRAM_DISK_DEVICE Disk;
- IO_OFFSET IoOffset;
- ULONG IrpReadWriteFlags;
- BOOL ReadWriteIrpPrepared;
- KSTATUS Status;
- BOOL ToIoBuffer;
- ASSERT(Irp->Direction == IrpDown);
- Disk = Irp->U.ReadWrite.DeviceContext;
- ReadWriteIrpPrepared = FALSE;
- ASSERT(IS_ALIGNED(Irp->U.ReadWrite.IoOffset, RAM_DISK_SECTOR_SIZE));
- ASSERT(IS_ALIGNED(Irp->U.ReadWrite.IoSizeInBytes, RAM_DISK_SECTOR_SIZE));
- ASSERT(Irp->U.ReadWrite.IoBuffer != NULL);
- Irp->U.ReadWrite.IoBytesCompleted = 0;
- IoOffset = Irp->U.ReadWrite.IoOffset;
- if (IoOffset >= Disk->Size) {
- Status = STATUS_OUT_OF_BOUNDS;
- goto DispatchIoEnd;
- }
- BytesToComplete = Irp->U.ReadWrite.IoSizeInBytes;
- if ((IoOffset + BytesToComplete) > Disk->Size) {
- BytesToComplete = Disk->Size - Irp->U.ReadWrite.IoOffset;
- }
- ToIoBuffer = TRUE;
- IrpReadWriteFlags = IRP_READ_WRITE_FLAG_POLLED;
- if (Irp->MinorCode == IrpMinorIoWrite) {
- ToIoBuffer = FALSE;
- IrpReadWriteFlags |= IRP_READ_WRITE_FLAG_WRITE;
- }
- //
- // Prepare the I/O buffer for polled I/O.
- //
- Status = IoPrepareReadWriteIrp(&(Irp->U.ReadWrite),
- 1,
- 0,
- MAX_ULONGLONG,
- IrpReadWriteFlags);
- if (!KSUCCESS(Status)) {
- goto DispatchIoEnd;
- }
- ReadWriteIrpPrepared = TRUE;
- //
- // Transfer the data between the disk and I/O buffer.
- //
- Status = MmCopyIoBufferData(Irp->U.ReadWrite.IoBuffer,
- (PUCHAR)Disk->Buffer + IoOffset,
- 0,
- BytesToComplete,
- ToIoBuffer);
- if (!KSUCCESS(Status)) {
- goto DispatchIoEnd;
- }
- Irp->U.ReadWrite.IoBytesCompleted = BytesToComplete;
- DispatchIoEnd:
- if (ReadWriteIrpPrepared != FALSE) {
- CompletionStatus = IoCompleteReadWriteIrp(&(Irp->U.ReadWrite),
- IrpReadWriteFlags);
- if (!KSUCCESS(CompletionStatus) && KSUCCESS(Status)) {
- Status = CompletionStatus;
- }
- }
- Irp->U.ReadWrite.NewIoOffset = IoOffset + Irp->U.ReadWrite.IoBytesCompleted;
- IoCompleteIrp(RamDiskDriver, Irp, Status);
- return;
- }
- VOID
- RamDiskDispatchSystemControl (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles System Control IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- PVOID Context;
- PRAM_DISK_DEVICE Disk;
- PSYSTEM_CONTROL_FILE_OPERATION FileOperation;
- PSYSTEM_CONTROL_LOOKUP Lookup;
- PFILE_PROPERTIES Properties;
- ULONGLONG PropertiesFileSize;
- KSTATUS Status;
- Context = Irp->U.SystemControl.SystemContext;
- Disk = DeviceContext;
- switch (Irp->MinorCode) {
- case IrpMinorSystemControlLookup:
- Lookup = (PSYSTEM_CONTROL_LOOKUP)Context;
- Status = STATUS_PATH_NOT_FOUND;
- if (Lookup->Root != FALSE) {
- //
- // Enable opening of the root as a single file.
- //
- Properties = &(Lookup->Properties);
- Properties->FileId = 0;
- Properties->Type = IoObjectBlockDevice;
- Properties->HardLinkCount = 1;
- Properties->BlockSize = RAM_DISK_SECTOR_SIZE;
- Properties->BlockCount = Disk->Size / RAM_DISK_SECTOR_SIZE;
- WRITE_INT64_SYNC(&(Properties->FileSize), Disk->Size);
- Lookup->Flags = LOOKUP_FLAG_NON_CACHED;
- Status = STATUS_SUCCESS;
- }
- IoCompleteIrp(RamDiskDriver, Irp, Status);
- break;
- //
- // Writes to the disk's properties are not allowed. Fail if the data
- // has changed.
- //
- case IrpMinorSystemControlWriteFileProperties:
- FileOperation = (PSYSTEM_CONTROL_FILE_OPERATION)Context;
- Properties = FileOperation->FileProperties;
- READ_INT64_SYNC(&(Properties->FileSize), &PropertiesFileSize);
- if ((Properties->FileId != 0) ||
- (Properties->Type != IoObjectBlockDevice) ||
- (Properties->HardLinkCount != 1) ||
- (Properties->BlockSize != RAM_DISK_SECTOR_SIZE) ||
- (Properties->BlockCount != (Disk->Size / RAM_DISK_SECTOR_SIZE)) ||
- (PropertiesFileSize != Disk->Size)) {
- Status = STATUS_NOT_SUPPORTED;
- } else {
- Status = STATUS_SUCCESS;
- }
- IoCompleteIrp(RamDiskDriver, Irp, Status);
- break;
- //
- // Do not support ramdisk device truncation.
- //
- case IrpMinorSystemControlTruncate:
- IoCompleteIrp(RamDiskDriver, Irp, STATUS_NOT_SUPPORTED);
- break;
- //
- // Gather and return device information.
- //
- case IrpMinorSystemControlDeviceInformation:
- IoCompleteIrp(RamDiskDriver, Irp, STATUS_NOT_SUPPORTED);
- break;
- case IrpMinorSystemControlSynchronize:
- IoCompleteIrp(RamDiskDriver, Irp, STATUS_SUCCESS);
- break;
- //
- // Ignore everything unrecognized.
- //
- default:
- ASSERT(FALSE);
- break;
- }
- return;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
|