[project] Rename winvblock__uint32 back to UINT32
[people/sha0/winvblock.git] / src / winvblock / ramdisk / ramdisk.c
1 /**
2  * Copyright (C) 2009-2011, Shao Miller <shao.miller@yrdsb.edu.on.ca>.
3  *
4  * This file is part of WinVBlock, derived from WinAoE.
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 /**
21  * @file
22  *
23  * RAM disk specifics.
24  */
25
26 #include <stdio.h>
27 #include <ntddk.h>
28
29 #include "winvblock.h"
30 #include "wv_stdlib.h"
31 #include "portable.h"
32 #include "driver.h"
33 #include "bus.h"
34 #include "device.h"
35 #include "disk.h"
36 #include "ramdisk.h"
37 #include "debug.h"
38
39 /*
40  * Yield a pointer to the RAM disk
41  */
42 #define ramdisk_get_ptr( dev_ptr ) \
43   ( ( WV_SP_RAMDISK_T ) ( disk__get_ptr ( dev_ptr ) )->ext )
44
45 /* Globals. */
46 static LIST_ENTRY ramdisk_list;
47 static KSPIN_LOCK ramdisk_list_lock;
48
49 /* Forward declarations. */
50 static WV_F_DEV_FREE free_ramdisk;
51 static WV_F_DISK_IO io;
52
53 /* With thanks to karyonix, who makes FiraDisk */
54 static __inline void STDCALL
55 fast_copy (
56   void *dest,
57   const void *src,
58   size_t count
59  )
60 {
61   __movsd ( dest, src, count >> 2 );
62 }
63
64 static NTSTATUS STDCALL io(
65     IN WV_SP_DEV_T dev_ptr,
66     IN WV_E_DISK_IO_MODE mode,
67     IN LONGLONG start_sector,
68     IN UINT32 sector_count,
69     IN PUCHAR buffer,
70     IN PIRP irp
71   ) {
72   PHYSICAL_ADDRESS PhysicalAddress;
73   PUCHAR PhysicalMemory;
74   WV_SP_DISK_T disk_ptr;
75   WV_SP_RAMDISK_T ramdisk_ptr;
76
77   /*
78    * Establish pointers to the disk and RAM disk
79    */
80   disk_ptr = disk__get_ptr ( dev_ptr );
81   ramdisk_ptr = ramdisk_get_ptr ( dev_ptr );
82
83   if ( sector_count < 1 )
84     {
85       /*
86        * A silly request 
87        */
88       DBG ( "sector_count < 1; cancelling\n" );
89       irp->IoStatus.Information = 0;
90       irp->IoStatus.Status = STATUS_CANCELLED;
91       IoCompleteRequest ( irp, IO_NO_INCREMENT );
92       return STATUS_CANCELLED;
93     }
94
95   PhysicalAddress.QuadPart =
96     ramdisk_ptr->DiskBuf + ( start_sector * disk_ptr->SectorSize );
97   /*
98    * Possible precision loss
99    */
100   PhysicalMemory =
101     MmMapIoSpace ( PhysicalAddress, sector_count * disk_ptr->SectorSize,
102                    MmNonCached );
103   if ( !PhysicalMemory )
104     {
105       DBG ( "Could not map memory for RAM disk!\n" );
106       irp->IoStatus.Information = 0;
107       irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
108       IoCompleteRequest ( irp, IO_NO_INCREMENT );
109       return STATUS_INSUFFICIENT_RESOURCES;
110     }
111   if (mode == WvDiskIoModeWrite)
112     fast_copy ( PhysicalMemory, buffer, sector_count * disk_ptr->SectorSize );
113   else
114     fast_copy ( buffer, PhysicalMemory, sector_count * disk_ptr->SectorSize );
115   MmUnmapIoSpace ( PhysicalMemory, sector_count * disk_ptr->SectorSize );
116   irp->IoStatus.Information = sector_count * disk_ptr->SectorSize;
117   irp->IoStatus.Status = STATUS_SUCCESS;
118   IoCompleteRequest ( irp, IO_NO_INCREMENT );
119   return STATUS_SUCCESS;
120 }
121
122 static UINT32 STDCALL query_id(
123     IN WV_SP_DEV_T dev,
124     IN BUS_QUERY_ID_TYPE query_type,
125     IN OUT WCHAR (*buf)[512]
126   ) {
127     WV_SP_DISK_T disk = disk__get_ptr(dev);
128     WV_SP_RAMDISK_T ramdisk = ramdisk_get_ptr(dev);
129     static PWCHAR hw_ids[WvDiskMediaTypes] = {
130         WVL_M_WLIT L"\\RAMFloppyDisk",
131         WVL_M_WLIT L"\\RAMHardDisk",
132         WVL_M_WLIT L"\\RAMOpticalDisc"
133       };
134
135     switch (query_type) {
136         case BusQueryDeviceID:
137           return swprintf(*buf, hw_ids[disk->Media]) + 1;
138
139         case BusQueryInstanceID:
140                 /* "Location" */
141           return swprintf(*buf, L"RAM_at_%08X", ramdisk->DiskBuf) + 1;
142
143         case BusQueryHardwareIDs: {
144             UINT32 tmp;
145
146             tmp = swprintf(*buf, hw_ids[disk->Media]) + 1;
147             tmp += swprintf(*buf + tmp, WvDiskCompatIds[disk->Media]) + 4;
148             return tmp;
149           }
150
151         case BusQueryCompatibleIDs:
152           return swprintf(*buf, WvDiskCompatIds[disk->Media]) + 4;
153
154         default:
155           return 0;
156       }
157   }
158
159 /**
160  * Create a new RAM disk
161  *
162  * @ret ramdisk_ptr     The address of a new RAM disk, or NULL for failure
163  *
164  * See the header file for additional details
165  */
166 WV_SP_RAMDISK_T
167 ramdisk__create (
168   void
169  )
170 {
171   WV_SP_DISK_T disk_ptr;
172   WV_SP_RAMDISK_T ramdisk_ptr;
173
174   /*
175    * Try to create a disk
176    */
177   disk_ptr = disk__create (  );
178   if ( disk_ptr == NULL )
179     goto err_nodisk;
180   /*
181    * RAM disk devices might be used for booting and should
182    * not be allocated from a paged memory pool
183    */
184   ramdisk_ptr = wv_mallocz(sizeof *ramdisk_ptr);
185   if ( ramdisk_ptr == NULL )
186     goto err_noramdisk;
187   /*
188    * Track the new RAM disk in our global list
189    */
190   ExInterlockedInsertTailList ( &ramdisk_list, &ramdisk_ptr->tracking,
191                                 &ramdisk_list_lock );
192   /*
193    * Populate non-zero device defaults
194    */
195   ramdisk_ptr->disk = disk_ptr;
196   ramdisk_ptr->prev_free = disk_ptr->Dev->Ops.Free;
197   disk_ptr->Dev->Ops.Free = free_ramdisk;
198   disk_ptr->Dev->Ops.PnpId = query_id;
199   disk_ptr->disk_ops.Io = io;
200   disk_ptr->ext = ramdisk_ptr;
201
202   return ramdisk_ptr;
203
204 err_noramdisk:
205
206   WvDevFree(disk_ptr->Dev);
207 err_nodisk:
208
209   return NULL;
210 }
211
212 /**
213  * Initialize the global, RAM disk-common environment.
214  *
215  * @ret ntstatus        STATUS_SUCCESS or the NTSTATUS for a failure.
216  */
217 NTSTATUS ramdisk__module_init(void) {
218     /* Initialize the global list of RAM disks. */
219     InitializeListHead(&ramdisk_list);
220     KeInitializeSpinLock(&ramdisk_list_lock);
221
222     return STATUS_SUCCESS;
223   }
224
225 /**
226  * Default RAM disk deletion operation.
227  *
228  * @v dev_ptr           Points to the RAM disk device to delete.
229  */
230 static void STDCALL free_ramdisk(IN WV_SP_DEV_T dev_ptr) {
231     WV_SP_DISK_T disk_ptr = disk__get_ptr(dev_ptr);
232     WV_SP_RAMDISK_T ramdisk_ptr = ramdisk_get_ptr(dev_ptr);
233     /* Free the "inherited class". */
234     ramdisk_ptr->prev_free(dev_ptr);
235     /*
236      * Track the RAM disk deletion in our global list.  Unfortunately,
237      * for now we have faith that a RAM disk won't be deleted twice and
238      * result in a race condition.  Something to keep in mind...
239      */
240     ExInterlockedRemoveHeadList(
241         ramdisk_ptr->tracking.Blink,
242                         &ramdisk_list_lock
243       );
244   
245     wv_free(ramdisk_ptr);
246   }