ramdisk.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  1. /*++
  2. Copyright (c) 2012 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. ramdisk.c
  5. Abstract:
  6. This module implements driver support for RAM disks. This RAM disk driver
  7. serves as an excellent simple example for Open, Close, I/O, and system
  8. control IRPs. It is fairly unusual (and therefore probably not a good
  9. example) in relation to its DriverEntry, AddDevice, and StateChange
  10. handling. Be aware of this if using this driver as a template to write
  11. your own.
  12. Author:
  13. Evan Green 17-Oct-2012
  14. Environment:
  15. Kernel
  16. --*/
  17. //
  18. // ------------------------------------------------------------------- Includes
  19. //
  20. #include <minoca/kernel/driver.h>
  21. #include <minoca/kernel/sysres.h>
  22. //
  23. // ---------------------------------------------------------------- Definitions
  24. //
  25. #define RAM_DISK_ALLOCATION_TAG 0x444D4152 // 'DMAR'
  26. #define RAM_DISK_SECTOR_SIZE 0x200
  27. //
  28. // --------------------------------------------------------------------- Macros
  29. //
  30. //
  31. // ------------------------------------------------------ Data Type Definitions
  32. //
  33. /*++
  34. Structure Description:
  35. This structure defines state associated with a RAM disk.
  36. Members:
  37. PhysicalAddress - Stores the physical address of the buffer.
  38. Buffer - Stores a pointer to the buffer of the raw RAM disk.
  39. Size - Stores the total size of the RAM disk, in bytes.
  40. --*/
  41. typedef struct _RAM_DISK_DEVICE {
  42. PHYSICAL_ADDRESS PhysicalAddress;
  43. PVOID Buffer;
  44. ULONGLONG Size;
  45. } RAM_DISK_DEVICE, *PRAM_DISK_DEVICE;
  46. //
  47. // ----------------------------------------------- Internal Function Prototypes
  48. //
  49. KSTATUS
  50. RamDiskAddDevice (
  51. PVOID Driver,
  52. PSTR DeviceId,
  53. PSTR ClassId,
  54. PSTR CompatibleIds,
  55. PVOID DeviceToken
  56. );
  57. VOID
  58. RamDiskDispatchStateChange (
  59. PIRP Irp,
  60. PVOID DeviceContext,
  61. PVOID IrpContext
  62. );
  63. VOID
  64. RamDiskDispatchOpen (
  65. PIRP Irp,
  66. PVOID DeviceContext,
  67. PVOID IrpContext
  68. );
  69. VOID
  70. RamDiskDispatchClose (
  71. PIRP Irp,
  72. PVOID DeviceContext,
  73. PVOID IrpContext
  74. );
  75. VOID
  76. RamDiskDispatchIo (
  77. PIRP Irp,
  78. PVOID DeviceContext,
  79. PVOID IrpContext
  80. );
  81. VOID
  82. RamDiskDispatchSystemControl (
  83. PIRP Irp,
  84. PVOID DeviceContext,
  85. PVOID IrpContext
  86. );
  87. //
  88. // -------------------------------------------------------------------- Globals
  89. //
  90. //
  91. // Store a pointer to the driver object.
  92. //
  93. PDRIVER RamDiskDriver = NULL;
  94. //
  95. // Store the next identifier.
  96. //
  97. volatile ULONG RamDiskNextIdentifier = 0;
  98. //
  99. // ------------------------------------------------------------------ Functions
  100. //
  101. KSTATUS
  102. DriverEntry (
  103. PDRIVER Driver
  104. )
  105. /*++
  106. Routine Description:
  107. This routine is the entry point for the RAM disk driver. It registers its
  108. other dispatch functions, and performs driver-wide initialization.
  109. Arguments:
  110. Driver - Supplies a pointer to the driver object.
  111. Return Value:
  112. STATUS_SUCCESS on success.
  113. Failure code on error.
  114. --*/
  115. {
  116. volatile ULONG DeviceId;
  117. CHAR DeviceIdString[11];
  118. DRIVER_FUNCTION_TABLE FunctionTable;
  119. PSYSTEM_RESOURCE_HEADER GenericHeader;
  120. PRAM_DISK_DEVICE RamDiskDevice;
  121. PSYSTEM_RESOURCE_RAM_DISK RamDiskResource;
  122. KSTATUS Status;
  123. RamDiskDriver = Driver;
  124. RtlZeroMemory(&FunctionTable, sizeof(DRIVER_FUNCTION_TABLE));
  125. FunctionTable.Version = DRIVER_FUNCTION_TABLE_VERSION;
  126. FunctionTable.AddDevice = RamDiskAddDevice;
  127. FunctionTable.DispatchStateChange = RamDiskDispatchStateChange;
  128. FunctionTable.DispatchOpen = RamDiskDispatchOpen;
  129. FunctionTable.DispatchClose = RamDiskDispatchClose;
  130. FunctionTable.DispatchIo = RamDiskDispatchIo;
  131. FunctionTable.DispatchSystemControl = RamDiskDispatchSystemControl;
  132. Status = IoRegisterDriverFunctions(Driver, &FunctionTable);
  133. if (!KSUCCESS(Status)) {
  134. goto DriverEntryEnd;
  135. }
  136. //
  137. // Get all RAM disks from the boot environment. This is not normally how
  138. // devices are created or enumerated. The RAM disk is special in that its
  139. // devices and resources are essentially born out of the boot environment.
  140. // Don't copy this loop if using this driver as a template.
  141. //
  142. while (TRUE) {
  143. GenericHeader = KeAcquireSystemResource(SystemResourceRamDisk);
  144. if (GenericHeader == NULL) {
  145. break;
  146. }
  147. RamDiskResource = (PSYSTEM_RESOURCE_RAM_DISK)GenericHeader;
  148. //
  149. // Allocate the internal data structure.
  150. //
  151. RamDiskDevice = MmAllocateNonPagedPool(sizeof(RAM_DISK_DEVICE),
  152. RAM_DISK_ALLOCATION_TAG);
  153. if (RamDiskDevice == NULL) {
  154. Status = STATUS_INSUFFICIENT_RESOURCES;
  155. goto DriverEntryEnd;
  156. }
  157. RtlZeroMemory(RamDiskDevice, sizeof(RAM_DISK_DEVICE));
  158. RamDiskDevice->PhysicalAddress =
  159. RamDiskResource->Header.PhysicalAddress;
  160. RamDiskDevice->Buffer = RamDiskResource->Header.VirtualAddress;
  161. RamDiskDevice->Size = RamDiskResource->Header.Size;
  162. DeviceId = RtlAtomicAdd32(&RamDiskNextIdentifier, 1);
  163. RtlPrintToString(DeviceIdString,
  164. 11,
  165. CharacterEncodingDefault,
  166. "RamDisk%x",
  167. DeviceId);
  168. //
  169. // Create the RAM disk device.
  170. //
  171. Status = IoCreateDevice(RamDiskDriver,
  172. RamDiskDevice,
  173. NULL,
  174. DeviceIdString,
  175. DISK_CLASS_ID,
  176. NULL,
  177. NULL);
  178. if (!KSUCCESS(Status)) {
  179. goto DriverEntryEnd;
  180. }
  181. }
  182. DriverEntryEnd:
  183. return Status;
  184. }
  185. KSTATUS
  186. RamDiskAddDevice (
  187. PVOID Driver,
  188. PSTR DeviceId,
  189. PSTR ClassId,
  190. PSTR CompatibleIds,
  191. PVOID DeviceToken
  192. )
  193. /*++
  194. Routine Description:
  195. This routine is called when a RAM disk is detected.
  196. Arguments:
  197. Driver - Supplies a pointer to the driver being called.
  198. DeviceId - Supplies a pointer to a string with the device ID.
  199. ClassId - Supplies a pointer to a string containing the device's class ID.
  200. CompatibleIds - Supplies a pointer to a string containing device IDs
  201. that would be compatible with this device.
  202. DeviceToken - Supplies an opaque token that the driver can use to identify
  203. the device in the system. This token should be used when attaching to
  204. the stack.
  205. Return Value:
  206. STATUS_SUCCESS on success.
  207. Failure code if the driver was unsuccessful in attaching itself.
  208. --*/
  209. {
  210. //
  211. // The RAM disk is not a real device, so it is not expected to be
  212. // attaching to emerging stacks. A proper driver should examine the device
  213. // ID and call IoAttachDriverToDevice to connect their driver to a newly
  214. // enumerated device.
  215. //
  216. return STATUS_NOT_IMPLEMENTED;
  217. }
  218. VOID
  219. RamDiskDispatchStateChange (
  220. PIRP Irp,
  221. PVOID DeviceContext,
  222. PVOID IrpContext
  223. )
  224. /*++
  225. Routine Description:
  226. This routine handles State Change IRPs.
  227. Arguments:
  228. Irp - Supplies a pointer to the I/O request packet.
  229. DeviceContext - Supplies the context pointer supplied by the driver when it
  230. attached itself to the driver stack. Presumably this pointer contains
  231. driver-specific device context.
  232. IrpContext - Supplies the context pointer supplied by the driver when
  233. the IRP was created.
  234. Return Value:
  235. None.
  236. --*/
  237. {
  238. BOOL CompleteIrp;
  239. KSTATUS Status;
  240. ASSERT(Irp->MajorCode == IrpMajorStateChange);
  241. //
  242. // The IRP is on its way down the stack. Do most processing here.
  243. //
  244. if (Irp->Direction == IrpDown) {
  245. Status = STATUS_NOT_SUPPORTED;
  246. CompleteIrp = TRUE;
  247. switch (Irp->MinorCode) {
  248. case IrpMinorQueryResources:
  249. Status = STATUS_SUCCESS;
  250. break;
  251. case IrpMinorStartDevice:
  252. Status = STATUS_SUCCESS;
  253. break;
  254. case IrpMinorQueryChildren:
  255. Irp->U.QueryChildren.Children = NULL;
  256. Irp->U.QueryChildren.ChildCount = 0;
  257. Status = STATUS_SUCCESS;
  258. break;
  259. //
  260. // Pass all other IRPs down.
  261. //
  262. default:
  263. CompleteIrp = FALSE;
  264. break;
  265. }
  266. //
  267. // Complete the IRP unless there's a reason not to. Normal drivers
  268. // should only complete the IRP if they're a bus driver or an error
  269. // occurred. The RAM disk is special as it created itself (and so it is
  270. // its own bus driver).
  271. //
  272. if (CompleteIrp != FALSE) {
  273. IoCompleteIrp(RamDiskDriver, Irp, Status);
  274. }
  275. //
  276. // The IRP is completed and is on its way back up. In normal device
  277. // drivers, this would be where to process the IRP, as by this point the
  278. // bus driver has performed necessary work (like enabling access to the
  279. // device on the bus in the case of start IRPs).
  280. //
  281. } else {
  282. ASSERT(Irp->Direction == IrpUp);
  283. }
  284. return;
  285. }
  286. VOID
  287. RamDiskDispatchOpen (
  288. PIRP Irp,
  289. PVOID DeviceContext,
  290. PVOID IrpContext
  291. )
  292. /*++
  293. Routine Description:
  294. This routine handles Open IRPs.
  295. Arguments:
  296. Irp - Supplies a pointer to the I/O request packet.
  297. DeviceContext - Supplies the context pointer supplied by the driver when it
  298. attached itself to the driver stack. Presumably this pointer contains
  299. driver-specific device context.
  300. IrpContext - Supplies the context pointer supplied by the driver when
  301. the IRP was created.
  302. Return Value:
  303. None.
  304. --*/
  305. {
  306. PRAM_DISK_DEVICE Disk;
  307. PRAM_DISK_DEVICE DiskCopy;
  308. Disk = (PRAM_DISK_DEVICE)DeviceContext;
  309. DiskCopy = MmAllocatePagedPool(sizeof(RAM_DISK_DEVICE),
  310. RAM_DISK_ALLOCATION_TAG);
  311. if (DiskCopy == NULL) {
  312. IoCompleteIrp(RamDiskDriver, Irp, STATUS_INSUFFICIENT_RESOURCES);
  313. return;
  314. }
  315. RtlCopyMemory(DiskCopy, Disk, sizeof(RAM_DISK_DEVICE));
  316. Irp->U.Open.DeviceContext = DiskCopy;
  317. IoCompleteIrp(RamDiskDriver, Irp, STATUS_SUCCESS);
  318. return;
  319. }
  320. VOID
  321. RamDiskDispatchClose (
  322. PIRP Irp,
  323. PVOID DeviceContext,
  324. PVOID IrpContext
  325. )
  326. /*++
  327. Routine Description:
  328. This routine handles Close IRPs.
  329. Arguments:
  330. Irp - Supplies a pointer to the I/O request packet.
  331. DeviceContext - Supplies the context pointer supplied by the driver when it
  332. attached itself to the driver stack. Presumably this pointer contains
  333. driver-specific device context.
  334. IrpContext - Supplies the context pointer supplied by the driver when
  335. the IRP was created.
  336. Return Value:
  337. None.
  338. --*/
  339. {
  340. MmFreePagedPool(Irp->U.Close.DeviceContext);
  341. IoCompleteIrp(RamDiskDriver, Irp, STATUS_SUCCESS);
  342. return;
  343. }
  344. VOID
  345. RamDiskDispatchIo (
  346. PIRP Irp,
  347. PVOID DeviceContext,
  348. PVOID IrpContext
  349. )
  350. /*++
  351. Routine Description:
  352. This routine handles I/O IRPs.
  353. Arguments:
  354. Irp - Supplies a pointer to the I/O request packet.
  355. DeviceContext - Supplies the context pointer supplied by the driver when it
  356. attached itself to the driver stack. Presumably this pointer contains
  357. driver-specific device context.
  358. IrpContext - Supplies the context pointer supplied by the driver when
  359. the IRP was created.
  360. Return Value:
  361. None.
  362. --*/
  363. {
  364. UINTN BytesToComplete;
  365. KSTATUS CompletionStatus;
  366. PRAM_DISK_DEVICE Disk;
  367. IO_OFFSET IoOffset;
  368. ULONG IrpReadWriteFlags;
  369. BOOL ReadWriteIrpPrepared;
  370. KSTATUS Status;
  371. BOOL ToIoBuffer;
  372. ASSERT(Irp->Direction == IrpDown);
  373. Disk = Irp->U.ReadWrite.DeviceContext;
  374. ReadWriteIrpPrepared = FALSE;
  375. ASSERT(IS_ALIGNED(Irp->U.ReadWrite.IoOffset, RAM_DISK_SECTOR_SIZE));
  376. ASSERT(IS_ALIGNED(Irp->U.ReadWrite.IoSizeInBytes, RAM_DISK_SECTOR_SIZE));
  377. ASSERT(Irp->U.ReadWrite.IoBuffer != NULL);
  378. Irp->U.ReadWrite.IoBytesCompleted = 0;
  379. IoOffset = Irp->U.ReadWrite.IoOffset;
  380. if (IoOffset >= Disk->Size) {
  381. Status = STATUS_OUT_OF_BOUNDS;
  382. goto DispatchIoEnd;
  383. }
  384. BytesToComplete = Irp->U.ReadWrite.IoSizeInBytes;
  385. if ((IoOffset + BytesToComplete) > Disk->Size) {
  386. BytesToComplete = Disk->Size - Irp->U.ReadWrite.IoOffset;
  387. }
  388. ToIoBuffer = TRUE;
  389. IrpReadWriteFlags = IRP_READ_WRITE_FLAG_POLLED;
  390. if (Irp->MinorCode == IrpMinorIoWrite) {
  391. ToIoBuffer = FALSE;
  392. IrpReadWriteFlags |= IRP_READ_WRITE_FLAG_WRITE;
  393. }
  394. //
  395. // Prepare the I/O buffer for polled I/O.
  396. //
  397. Status = IoPrepareReadWriteIrp(&(Irp->U.ReadWrite),
  398. 1,
  399. 0,
  400. MAX_ULONGLONG,
  401. IrpReadWriteFlags);
  402. if (!KSUCCESS(Status)) {
  403. goto DispatchIoEnd;
  404. }
  405. ReadWriteIrpPrepared = TRUE;
  406. //
  407. // Transfer the data between the disk and I/O buffer.
  408. //
  409. Status = MmCopyIoBufferData(Irp->U.ReadWrite.IoBuffer,
  410. (PUCHAR)Disk->Buffer + IoOffset,
  411. 0,
  412. BytesToComplete,
  413. ToIoBuffer);
  414. if (!KSUCCESS(Status)) {
  415. goto DispatchIoEnd;
  416. }
  417. Irp->U.ReadWrite.IoBytesCompleted = BytesToComplete;
  418. DispatchIoEnd:
  419. if (ReadWriteIrpPrepared != FALSE) {
  420. CompletionStatus = IoCompleteReadWriteIrp(&(Irp->U.ReadWrite),
  421. IrpReadWriteFlags);
  422. if (!KSUCCESS(CompletionStatus) && KSUCCESS(Status)) {
  423. Status = CompletionStatus;
  424. }
  425. }
  426. Irp->U.ReadWrite.NewIoOffset = IoOffset + Irp->U.ReadWrite.IoBytesCompleted;
  427. IoCompleteIrp(RamDiskDriver, Irp, Status);
  428. return;
  429. }
  430. VOID
  431. RamDiskDispatchSystemControl (
  432. PIRP Irp,
  433. PVOID DeviceContext,
  434. PVOID IrpContext
  435. )
  436. /*++
  437. Routine Description:
  438. This routine handles System Control IRPs.
  439. Arguments:
  440. Irp - Supplies a pointer to the I/O request packet.
  441. DeviceContext - Supplies the context pointer supplied by the driver when it
  442. attached itself to the driver stack. Presumably this pointer contains
  443. driver-specific device context.
  444. IrpContext - Supplies the context pointer supplied by the driver when
  445. the IRP was created.
  446. Return Value:
  447. None.
  448. --*/
  449. {
  450. PVOID Context;
  451. PRAM_DISK_DEVICE Disk;
  452. PSYSTEM_CONTROL_FILE_OPERATION FileOperation;
  453. PSYSTEM_CONTROL_LOOKUP Lookup;
  454. PFILE_PROPERTIES Properties;
  455. ULONGLONG PropertiesFileSize;
  456. KSTATUS Status;
  457. Context = Irp->U.SystemControl.SystemContext;
  458. Disk = DeviceContext;
  459. switch (Irp->MinorCode) {
  460. case IrpMinorSystemControlLookup:
  461. Lookup = (PSYSTEM_CONTROL_LOOKUP)Context;
  462. Status = STATUS_PATH_NOT_FOUND;
  463. if (Lookup->Root != FALSE) {
  464. //
  465. // Enable opening of the root as a single file.
  466. //
  467. Properties = &(Lookup->Properties);
  468. Properties->FileId = 0;
  469. Properties->Type = IoObjectBlockDevice;
  470. Properties->HardLinkCount = 1;
  471. Properties->BlockSize = RAM_DISK_SECTOR_SIZE;
  472. Properties->BlockCount = Disk->Size / RAM_DISK_SECTOR_SIZE;
  473. WRITE_INT64_SYNC(&(Properties->FileSize), Disk->Size);
  474. Lookup->Flags = LOOKUP_FLAG_NON_CACHED;
  475. Status = STATUS_SUCCESS;
  476. }
  477. IoCompleteIrp(RamDiskDriver, Irp, Status);
  478. break;
  479. //
  480. // Writes to the disk's properties are not allowed. Fail if the data
  481. // has changed.
  482. //
  483. case IrpMinorSystemControlWriteFileProperties:
  484. FileOperation = (PSYSTEM_CONTROL_FILE_OPERATION)Context;
  485. Properties = FileOperation->FileProperties;
  486. READ_INT64_SYNC(&(Properties->FileSize), &PropertiesFileSize);
  487. if ((Properties->FileId != 0) ||
  488. (Properties->Type != IoObjectBlockDevice) ||
  489. (Properties->HardLinkCount != 1) ||
  490. (Properties->BlockSize != RAM_DISK_SECTOR_SIZE) ||
  491. (Properties->BlockCount != (Disk->Size / RAM_DISK_SECTOR_SIZE)) ||
  492. (PropertiesFileSize != Disk->Size)) {
  493. Status = STATUS_NOT_SUPPORTED;
  494. } else {
  495. Status = STATUS_SUCCESS;
  496. }
  497. IoCompleteIrp(RamDiskDriver, Irp, Status);
  498. break;
  499. //
  500. // Do not support ramdisk device truncation.
  501. //
  502. case IrpMinorSystemControlTruncate:
  503. IoCompleteIrp(RamDiskDriver, Irp, STATUS_NOT_SUPPORTED);
  504. break;
  505. //
  506. // Gather and return device information.
  507. //
  508. case IrpMinorSystemControlDeviceInformation:
  509. IoCompleteIrp(RamDiskDriver, Irp, STATUS_NOT_SUPPORTED);
  510. break;
  511. case IrpMinorSystemControlSynchronize:
  512. IoCompleteIrp(RamDiskDriver, Irp, STATUS_SUCCESS);
  513. break;
  514. //
  515. // Ignore everything unrecognized.
  516. //
  517. default:
  518. ASSERT(FALSE);
  519. break;
  520. }
  521. return;
  522. }
  523. //
  524. // --------------------------------------------------------- Internal Functions
  525. //