/*++ Copyright (c) 2012 Minoca Corp. All Rights Reserved Module Name: fatio.c Abstract: This module implements the underlying device support for the FAT library when running as a kernel-mode driver. Author: Evan Green 25-Sep-2012 Environment: Kernel --*/ // // ------------------------------------------------------------------- Includes // #include #include // // ---------------------------------------------------------------- Definitions // // // ------------------------------------------------------ Data Type Definitions // /*++ Structure Description: This structure stores information about a block device backing a FAT file system. Members: BlockDevice - Stores the block device parameters for the device. --*/ typedef struct _FAT_DEVICE { BLOCK_DEVICE_PARAMETERS BlockDevice; } FAT_DEVICE, *PFAT_DEVICE; // // ----------------------------------------------- Internal Function Prototypes // // // -------------------------------------------------------------------- Globals // // // ------------------------------------------------------------------ Functions // PFAT_IO_BUFFER FatAllocateIoBuffer ( PVOID DeviceToken, UINTN Size ) /*++ Routine Description: This routine allocates memory for device I/O use. Arguments: DeviceToken - Supplies an opaque token identifying the underlying device. Size - Supplies the size of the required allocation, in bytes. Return Value: Returns a pointer to the FAT I/O buffer, or NULL on failure. --*/ { PIO_BUFFER IoBuffer; IoBuffer = MmAllocateUninitializedIoBuffer(Size, 0); return (PFAT_IO_BUFFER)IoBuffer; } PFAT_IO_BUFFER FatCreateIoBuffer ( PVOID Buffer, UINTN Size ) /*++ Routine Description: This routine creates a FAT I/O buffer from the given buffer. Arguments: Buffer - Supplies a pointer to the memory buffer on which to base the FAT I/O buffer. Size - Supplies the size of the memory buffer, in bytes. Return Value: Returns an pointer to the FAT I/O buffer, or NULL on failure. --*/ { PIO_BUFFER IoBuffer; KSTATUS Status; Status = MmCreateIoBuffer(Buffer, Size, IO_BUFFER_FLAG_KERNEL_MODE_DATA, &IoBuffer); if (!KSUCCESS(Status)) { return NULL; } return (PFAT_IO_BUFFER)IoBuffer; } VOID FatIoBufferUpdateOffset ( PFAT_IO_BUFFER FatIoBuffer, UINTN OffsetUpdate, BOOL Decrement ) /*++ Routine Description: This routine increments the given FAT I/O buffer's current offset by the given amount. Arguments: FatIoBuffer - Supplies a pointer to a FAT I/O buffer. OffsetUpdate - Supplies the number of bytes by which the offset will be updated. Decrement - Supplies a boolean indicating whether the update will be a decrement (TRUE) or an increment (FALSE). Return Value: None. --*/ { if (Decrement == FALSE) { MmIoBufferIncrementOffset((PIO_BUFFER)FatIoBuffer, OffsetUpdate); } else { MmIoBufferDecrementOffset((PIO_BUFFER)FatIoBuffer, OffsetUpdate); } return; } VOID FatIoBufferSetOffset ( PFAT_IO_BUFFER FatIoBuffer, UINTN Offset ) /*++ Routine Description: This routine sets the given FAT I/O buffer's current offset. Arguments: FatIoBuffer - Supplies a pointer to a FAT I/O buffer. Offset - Supplies the new offset to set. Return Value: None. --*/ { MmSetIoBufferCurrentOffset((PIO_BUFFER)FatIoBuffer, Offset); return; } KSTATUS FatZeroIoBuffer ( PFAT_IO_BUFFER FatIoBuffer, UINTN Offset, UINTN ByteCount ) /*++ Routine Description: This routine zeros the contents of the FAT I/O buffer starting at the offset for the given number of bytes. Arguments: FatIoBuffer - Supplies a pointer to the FAT I/O buffer that is to be zeroed. Offset - Supplies the offset within the I/O buffer where the zeroing should begin. ByteCount - Supplies the number of bytes to zero. Return Value: Status code. --*/ { return MmZeroIoBuffer((PIO_BUFFER)FatIoBuffer, Offset, ByteCount); } KSTATUS FatCopyIoBuffer ( PFAT_IO_BUFFER Destination, UINTN DestinationOffset, PFAT_IO_BUFFER Source, UINTN SourceOffset, UINTN ByteCount ) /*++ Routine Description: This routine copies the contents of the source I/O buffer starting at the source offset to the destination I/O buffer starting at the destination offset. It assumes that the arguments are correct such that the copy can succeed. Arguments: Destination - Supplies a pointer to the destination I/O buffer that is to be copied into. DestinationOffset - Supplies the offset into the destination I/O buffer where the copy should begin. Source - Supplies a pointer to the source I/O buffer whose contents will be copied to the destination. SourceOffset - Supplies the offset into the source I/O buffer where the copy should begin. ByteCount - Supplies the size of the requested copy in bytes. Return Value: Status code. --*/ { KSTATUS Status; Status = MmCopyIoBuffer((PIO_BUFFER)Destination, DestinationOffset, (PIO_BUFFER)Source, SourceOffset, ByteCount); return Status; } KSTATUS FatCopyIoBufferData ( PFAT_IO_BUFFER FatIoBuffer, PVOID Buffer, UINTN Offset, UINTN Size, BOOL ToIoBuffer ) /*++ Routine Description: This routine copies from a buffer into the given I/O buffer or out of the given I/O buffer. Arguments: FatIoBuffer - Supplies a pointer to the FAT I/O buffer to copy in or out of. Buffer - Supplies a pointer to the regular linear buffer to copy to or from. Offset - Supplies an offset in bytes from the beginning of the I/O buffer to copy to or from. Size - Supplies the number of bytes to copy. ToIoBuffer - Supplies a boolean indicating whether data is copied into the I/O buffer (TRUE) or out of the I/O buffer (FALSE). Return Value: Status code. --*/ { KSTATUS Status; Status = MmCopyIoBufferData((PIO_BUFFER)FatIoBuffer, Buffer, Offset, Size, ToIoBuffer); return Status; } PVOID FatMapIoBuffer ( PFAT_IO_BUFFER FatIoBuffer ) /*++ Routine Description: This routine maps the given FAT I/O buffer and returns the base of the virtually contiguous mapping. Arguments: FatIoBuffer - Supplies a pointer to a FAT I/O buffer. Return Value: Returns a pointer to the virtual address of the mapping on success, or NULL on failure. --*/ { PIO_BUFFER IoBuffer; KSTATUS Status; IoBuffer = (PFAT_IO_BUFFER)FatIoBuffer; Status = MmMapIoBuffer(IoBuffer, FALSE, FALSE, TRUE); if (!KSUCCESS(Status)) { return NULL; } return IoBuffer->Fragment[0].VirtualAddress; } VOID FatFreeIoBuffer ( PFAT_IO_BUFFER FatIoBuffer ) /*++ Routine Description: This routine frees a FAT I/O buffer. Arguments: FatIoBuffer - Supplies a pointer to a FAT I/O buffer. Return Value: None. --*/ { MmFreeIoBuffer((PIO_BUFFER)FatIoBuffer); return; } PVOID FatAllocatePagedMemory ( PVOID DeviceToken, ULONG SizeInBytes ) /*++ Routine Description: This routine allocates paged memory for the FAT library. Arguments: DeviceToken - Supplies an opaque token identifying the underlying device. SizeInBytes - Supplies the number of bytes to allocate. Return Value: Returns a pointer to the allocated memory, or NULL on failure. --*/ { return MmAllocatePagedPool(SizeInBytes, FAT_ALLOCATION_TAG); } PVOID FatAllocateNonPagedMemory ( PVOID DeviceToken, ULONG SizeInBytes ) /*++ Routine Description: This routine allocates non-paged memory for the FAT library. Arguments: DeviceToken - Supplies an opaque token identifying the underlying device. SizeInBytes - Supplies the number of bytes to allocate. Return Value: Returns a pointer to the allocated memory, or NULL on failure. --*/ { return MmAllocateNonPagedPool(SizeInBytes, FAT_ALLOCATION_TAG); } VOID FatFreePagedMemory ( PVOID DeviceToken, PVOID Allocation ) /*++ Routine Description: This routine frees paged memory for the FAT library. Arguments: DeviceToken - Supplies an opaque token identifying the underlying device. Allocation - Supplies a pointer to the allocation to free. Return Value: None. --*/ { MmFreePagedPool(Allocation); return; } VOID FatFreeNonPagedMemory ( PVOID DeviceToken, PVOID Allocation ) /*++ Routine Description: This routine frees memory for the FAT library. Arguments: DeviceToken - Supplies an opaque token identifying the underlying device. Allocation - Supplies a pointer to the allocation to free. Return Value: None. --*/ { MmFreeNonPagedPool(Allocation); return; } KSTATUS FatCreateLock ( PVOID *Lock ) /*++ Routine Description: This routine creates a lock. Arguments: Lock - Supplies a pointer where an opaque pointer will be returned representing the lock. Return Value: STATUS_SUCCESS on success. STATUS_INSUFFICIENT_RESOURCES if the lock could not be allocated. --*/ { PQUEUED_LOCK NewLock; NewLock = KeCreateQueuedLock(); if (NewLock == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } *Lock = NewLock; return STATUS_SUCCESS; } VOID FatDestroyLock ( PVOID Lock ) /*++ Routine Description: This routine destroys a created lock. Arguments: Lock - Supplies a the opaque pointer returned upon creation. Return Value: None. --*/ { KeDestroyQueuedLock(Lock); return; } VOID FatAcquireLock ( PVOID Lock ) /*++ Routine Description: This routine acquires a lock. Arguments: Lock - Supplies a the opaque pointer returned upon creation. Return Value: None. --*/ { KeAcquireQueuedLock(Lock); return; } VOID FatReleaseLock ( PVOID Lock ) /*++ Routine Description: This routine releases a lock. Arguments: Lock - Supplies a the opaque pointer returned upon creation. Return Value: None. --*/ { KeReleaseQueuedLock(Lock); return; } KSTATUS FatOpenDevice ( PBLOCK_DEVICE_PARAMETERS BlockParameters ) /*++ Routine Description: This routine opens the underlying device that the FAT file system reads and writes blocks to. Arguments: BlockParameters - Supplies the initial block device parameters for the device. These parameters may be modified by this call. Return Value: STATUS_SUCCESS on success. STATUS_INSUFFICIENT_RESOURCES if there were not enough resources to open the device. --*/ { PFAT_DEVICE FatDevice; FatDevice = MmAllocateNonPagedPool(sizeof(FAT_DEVICE), FAT_ALLOCATION_TAG); if (FatDevice == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } FatDevice->BlockDevice = *BlockParameters; // // Overwrite the device token so this layer gets this pointer. // BlockParameters->DeviceToken = FatDevice; return STATUS_SUCCESS; } VOID FatCloseDevice ( PVOID DeviceToken ) /*++ Routine Description: This routine closes the device backing the FAT file system. Arguments: DeviceToken - Supplies a pointer to the device token returned upon opening the underlying device. Return Value: None. --*/ { MmFreeNonPagedPool(DeviceToken); return; } KSTATUS FatReadDevice ( PVOID DeviceToken, ULONGLONG BlockAddress, UINTN BlockCount, ULONG Flags, PVOID Irp, PFAT_IO_BUFFER FatIoBuffer ) /*++ Routine Description: This routine reads data from the underlying disk. Arguments: DeviceToken - Supplies an opaque token identifying the underlying device. BlockAddress - Supplies the block index to read (for physical disks, this is the LBA). BlockCount - Supplies the number of blocks to read. Flags - Supplies flags regarding the I/O operation. See IO_FLAG_* definitions. Irp - Supplies an optional pointer to the IRP to pass to the read file function. FatIoBuffer - Supplies a pointer to a FAT I/O buffer where the data from the disk will be returned. Return Value: Status code. --*/ { ULONG BlockSize; UINTN BytesCompleted; PFAT_DEVICE FatDevice; PIO_BUFFER IoBuffer; UINTN SizeInBytes; KSTATUS Status; IoBuffer = (PIO_BUFFER)FatIoBuffer; FatDevice = (PFAT_DEVICE)DeviceToken; BlockSize = FatDevice->BlockDevice.BlockSize; SizeInBytes = BlockCount * BlockSize; ASSERT(IoBuffer != NULL); Status = IoReadAtOffset(FatDevice->BlockDevice.DeviceToken, IoBuffer, BlockAddress * BlockSize, SizeInBytes, Flags, WAIT_TIME_INDEFINITE, &BytesCompleted, Irp); if (!KSUCCESS(Status)) { goto ReadDeviceEnd; } if (BytesCompleted != SizeInBytes) { ASSERT(FALSE); Status = STATUS_DATA_LENGTH_MISMATCH; goto ReadDeviceEnd; } ReadDeviceEnd: return Status; } KSTATUS FatWriteDevice ( PVOID DeviceToken, ULONGLONG BlockAddress, UINTN BlockCount, ULONG Flags, PVOID Irp, PFAT_IO_BUFFER FatIoBuffer ) /*++ Routine Description: This routine writes data to the underlying disk. Arguments: DeviceToken - Supplies an opaque token identifying the underlying device. BlockAddress - Supplies the block index to write to (for physical disks, this is the LBA). BlockCount - Supplies the number of blocks to write. Flags - Supplies flags regarding the I/O operation. See IO_FLAG_* definitions. Irp - Supplies an optional pointer to an IRP to use for the disk operation. FatIoBuffer - Supplies a pointer to a FAT I/O buffer containing the data to write. Return Value: Status code. --*/ { ULONG BlockSize; UINTN BytesCompleted; PFAT_DEVICE FatDevice; KSTATUS Status; FatDevice = (PFAT_DEVICE)DeviceToken; BlockSize = FatDevice->BlockDevice.BlockSize; Status = IoWriteAtOffset(FatDevice->BlockDevice.DeviceToken, (PIO_BUFFER)FatIoBuffer, BlockAddress * BlockSize, BlockCount * BlockSize, Flags, WAIT_TIME_INDEFINITE, &BytesCompleted, Irp); if (!KSUCCESS(Status)) { goto WriteDeviceEnd; } if (BytesCompleted != (BlockCount * BlockSize)) { ASSERT(FALSE); Status = STATUS_DATA_LENGTH_MISMATCH; goto WriteDeviceEnd; } WriteDeviceEnd: return Status; } KSTATUS FatGetDeviceBlockInformation ( PVOID DeviceToken, PFILE_BLOCK_INFORMATION BlockInformation ) /*++ Routine Description: This routine converts a file's block information into disk level block information by modifying the offsets of each contiguous run. Arguments: DeviceToken - Supplies an opaque token identify the underlying device. BlockInformation - Supplies a pointer to the block information to be updated. Return Value: Status code. --*/ { PFAT_DEVICE FatDevice; KSTATUS Status; ASSERT(BlockInformation != NULL); FatDevice = (PFAT_DEVICE)DeviceToken; Status = IoGetFileBlockInformation(FatDevice->BlockDevice.DeviceToken, &BlockInformation); return Status; } ULONG FatGetIoCacheEntryDataSize ( VOID ) /*++ Routine Description: This routine returns the size of data stored in each cache entry. Arguments: None. Return Value: Returns the size of the data stored in each cache entry, or 0 if there is no cache. --*/ { return IoGetCacheEntryDataSize(); } ULONG FatGetPageSize ( VOID ) /*++ Routine Description: This routine returns the size of a physical memory page for the current FAT environment. Arguments: None. Return Value: Returns the size of a page in the current environment. Returns 0 if the size is not known. --*/ { return MmPageSize(); } VOID FatGetCurrentSystemTime ( PSYSTEM_TIME SystemTime ) /*++ Routine Description: This routine returns the current system time. Arguments: SystemTime - Supplies a pointer where the current system time will be returned. Return Value: None. --*/ { KeGetSystemTime(SystemTime); return; } // // --------------------------------------------------------- Internal Functions //