2 * Copyright (C) 2009-2010, Shao Miller <shao.miller@yrdsb.edu.on.ca>.
4 * This file is part of WinVBlock, derived from WinAoE.
6 * WinVBlock is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * WinVBlock is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with WinVBlock. If not, see <http://www.gnu.org/licenses/>.
29 #include "winvblock.h"
30 #include "wv_stdlib.h"
39 * Yield a pointer to the RAM disk
41 #define ramdisk_get_ptr( dev_ptr ) \
42 ( ( ramdisk__type_ptr ) ( disk__get_ptr ( dev_ptr ) )->ext )
45 static LIST_ENTRY ramdisk_list;
46 static KSPIN_LOCK ramdisk_list_lock;
48 /* Forward declarations. */
49 static WV_F_DEV_FREE free_ramdisk;
51 /* With thanks to karyonix, who makes FiraDisk */
52 static __inline void STDCALL
59 __movsd ( dest, src, count >> 2 );
67 PHYSICAL_ADDRESS PhysicalAddress;
68 winvblock__uint8_ptr PhysicalMemory;
69 disk__type_ptr disk_ptr;
70 ramdisk__type_ptr ramdisk_ptr;
73 * Establish pointers to the disk and RAM disk
75 disk_ptr = disk__get_ptr ( dev_ptr );
76 ramdisk_ptr = ramdisk_get_ptr ( dev_ptr );
78 if ( sector_count < 1 )
83 DBG ( "sector_count < 1; cancelling\n" );
84 irp->IoStatus.Information = 0;
85 irp->IoStatus.Status = STATUS_CANCELLED;
86 IoCompleteRequest ( irp, IO_NO_INCREMENT );
87 return STATUS_CANCELLED;
90 PhysicalAddress.QuadPart =
91 ramdisk_ptr->DiskBuf + ( start_sector * disk_ptr->SectorSize );
93 * Possible precision loss
96 MmMapIoSpace ( PhysicalAddress, sector_count * disk_ptr->SectorSize,
98 if ( !PhysicalMemory )
100 DBG ( "Could not map memory for RAM disk!\n" );
101 irp->IoStatus.Information = 0;
102 irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
103 IoCompleteRequest ( irp, IO_NO_INCREMENT );
104 return STATUS_INSUFFICIENT_RESOURCES;
106 if (mode == WvDiskIoModeWrite)
107 fast_copy ( PhysicalMemory, buffer, sector_count * disk_ptr->SectorSize );
109 fast_copy ( buffer, PhysicalMemory, sector_count * disk_ptr->SectorSize );
110 MmUnmapIoSpace ( PhysicalMemory, sector_count * disk_ptr->SectorSize );
111 irp->IoStatus.Information = sector_count * disk_ptr->SectorSize;
112 irp->IoStatus.Status = STATUS_SUCCESS;
113 IoCompleteRequest ( irp, IO_NO_INCREMENT );
114 return STATUS_SUCCESS;
117 static winvblock__uint32 STDCALL query_id(
119 IN BUS_QUERY_ID_TYPE query_type,
120 IN OUT WCHAR (*buf)[512]
122 disk__type_ptr disk = disk__get_ptr(dev);
123 ramdisk__type_ptr ramdisk = ramdisk_get_ptr(dev);
124 static PWCHAR hw_ids[WvDiskMediaTypes] = {
125 winvblock__literal_w L"\\RAMFloppyDisk",
126 winvblock__literal_w L"\\RAMHardDisk",
127 winvblock__literal_w L"\\RAMOpticalDisc"
130 switch (query_type) {
131 case BusQueryDeviceID:
132 return swprintf(*buf, hw_ids[disk->Media]) + 1;
134 case BusQueryInstanceID:
136 return swprintf(*buf, L"RAM_at_%08X", ramdisk->DiskBuf) + 1;
138 case BusQueryHardwareIDs: {
139 winvblock__uint32 tmp;
141 tmp = swprintf(*buf, hw_ids[disk->Media]) + 1;
142 tmp += swprintf(*buf + tmp, WvDiskCompatIds[disk->Media]) + 4;
146 case BusQueryCompatibleIDs:
147 return swprintf(*buf, WvDiskCompatIds[disk->Media]) + 4;
155 * Create a new RAM disk
157 * @ret ramdisk_ptr The address of a new RAM disk, or NULL for failure
159 * See the header file for additional details
166 disk__type_ptr disk_ptr;
167 ramdisk__type_ptr ramdisk_ptr;
170 * Try to create a disk
172 disk_ptr = disk__create ( );
173 if ( disk_ptr == NULL )
176 * RAM disk devices might be used for booting and should
177 * not be allocated from a paged memory pool
179 ramdisk_ptr = wv_mallocz(sizeof *ramdisk_ptr);
180 if ( ramdisk_ptr == NULL )
183 * Track the new RAM disk in our global list
185 ExInterlockedInsertTailList ( &ramdisk_list, &ramdisk_ptr->tracking,
186 &ramdisk_list_lock );
188 * Populate non-zero device defaults
190 ramdisk_ptr->disk = disk_ptr;
191 ramdisk_ptr->prev_free = disk_ptr->device->Ops.Free;
192 disk_ptr->device->Ops.Free = free_ramdisk;
193 disk_ptr->device->Ops.PnpId = query_id;
194 disk_ptr->disk_ops.io = io;
195 disk_ptr->ext = ramdisk_ptr;
201 WvDevFree(disk_ptr->device);
208 * Initialize the global, RAM disk-common environment.
210 * @ret ntstatus STATUS_SUCCESS or the NTSTATUS for a failure.
212 NTSTATUS ramdisk__module_init(void) {
213 /* Initialize the global list of RAM disks. */
214 InitializeListHead(&ramdisk_list);
215 KeInitializeSpinLock(&ramdisk_list_lock);
217 return STATUS_SUCCESS;
221 * Default RAM disk deletion operation.
223 * @v dev_ptr Points to the RAM disk device to delete.
225 static void STDCALL free_ramdisk(IN WV_SP_DEV_T dev_ptr) {
226 disk__type_ptr disk_ptr = disk__get_ptr(dev_ptr);
227 ramdisk__type_ptr ramdisk_ptr = ramdisk_get_ptr(dev_ptr);
228 /* Free the "inherited class". */
229 ramdisk_ptr->prev_free(dev_ptr);
231 * Track the RAM disk deletion in our global list. Unfortunately,
232 * for now we have faith that a RAM disk won't be deleted twice and
233 * result in a race condition. Something to keep in mind...
235 ExInterlockedRemoveHeadList(
236 ramdisk_ptr->tracking.Blink,
240 wv_free(ramdisk_ptr);