Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

714 lines
19 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. XIPDisk.c
  5. Abstract:
  6. This is the XIP Disk driver for Whistler NT/Embedded.
  7. Author:
  8. DavePr 18-Sep-2000 -- base one NT4 DDK ramdisk by RobertN 10-Mar-1993.
  9. Environment:
  10. Kernel mode only.
  11. Notes:
  12. Revision History:
  13. --*/
  14. //
  15. // Include files.
  16. //
  17. #include <ntddk.h>
  18. #include "initguid.h"
  19. #include "mountdev.h"
  20. #include <ntdddisk.h> // Disk device IOCTLs, DiskClassGuid
  21. #include "fat.h"
  22. #include "xip.h"
  23. #include "XIPDisk.h"
  24. //
  25. // ISSUE-2000/10/11-DavePr -- haven't decided how to define DO_XIP appropriately.
  26. //
  27. #ifndef DO_XIP
  28. #define DO_XIP 0x00020000
  29. #endif
  30. #include <string.h>
  31. NTSTATUS
  32. XIPDiskCreateClose(
  33. IN PDEVICE_OBJECT DeviceObject,
  34. IN PIRP Irp
  35. )
  36. /*++
  37. Routine Description:
  38. This routine is called by the I/O system when the XIPDisk is opened or
  39. closed.
  40. No action is performed other than completing the request successfully.
  41. Arguments:
  42. DeviceObject - a pointer to the object that represents the device
  43. that I/O is to be done on.
  44. Irp - a pointer to the I/O Request Packet for this request.
  45. Return Value:
  46. STATUS_INVALID_PARAMETER if parameters are invalid,
  47. STATUS_SUCCESS otherwise.
  48. --*/
  49. {
  50. PXIPDISK_EXTENSION diskExtension = NULL; // ptr to device extension
  51. PBIOS_PARAMETER_BLOCK bios;
  52. NTSTATUS status;
  53. diskExtension = DeviceObject->DeviceExtension;
  54. status = XIPDispatch(XIPCMD_NOOP, NULL, 0);
  55. if (!NT_SUCCESS(status) || !diskExtension->BootParameters.BasePage) {
  56. status = STATUS_DEVICE_NOT_READY;
  57. } else {
  58. status = STATUS_SUCCESS;
  59. }
  60. Irp->IoStatus.Status = status;
  61. Irp->IoStatus.Information = 0;
  62. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  63. return status;
  64. }
  65. NTSTATUS
  66. XIPDiskReadWrite(
  67. IN PDEVICE_OBJECT DeviceObject,
  68. IN PIRP Irp
  69. )
  70. /*++
  71. Routine Description:
  72. This routine is called by the I/O system to read or write to a
  73. device that we control.
  74. Arguments:
  75. DeviceObject - a pointer to the object that represents the device
  76. that I/O is to be done on.
  77. Irp - a pointer to the I/O Request Packet for this request.
  78. Return Value:
  79. STATUS_INVALID_PARAMETER if parameters are invalid,
  80. STATUS_SUCCESS otherwise.
  81. --*/
  82. {
  83. PXIPDISK_EXTENSION diskExtension;
  84. PIO_STACK_LOCATION irpSp;
  85. PUCHAR bufferAddress, diskByteAddress;
  86. PUCHAR romPageAddress = NULL;
  87. ULONG_PTR ioOffset;
  88. ULONG ioLength;
  89. NTSTATUS status;
  90. PHYSICAL_ADDRESS physicalAddress;
  91. ULONG mappingSize;
  92. //
  93. // Set up necessary object and extension pointers.
  94. //
  95. diskExtension = DeviceObject->DeviceExtension;
  96. irpSp = IoGetCurrentIrpStackLocation(Irp);
  97. //
  98. // Check for invalid parameters. It is an error for the starting offset
  99. // + length to go past the end of the buffer, or for the offset or length
  100. // not to be a proper multiple of the sector size.
  101. //
  102. // Others are possible, but we don't check them since we trust the
  103. // file system and they aren't deadly.
  104. //
  105. if (irpSp->Parameters.Read.ByteOffset.HighPart) {
  106. status = STATUS_INVALID_PARAMETER;
  107. goto done;
  108. }
  109. ioOffset = irpSp->Parameters.Read.ByteOffset.LowPart;
  110. ioLength = irpSp->Parameters.Read.Length;
  111. if (ioLength == 0) {
  112. status = STATUS_SUCCESS;
  113. goto done;
  114. }
  115. if (ioOffset + ioLength < ioOffset) {
  116. status = STATUS_INVALID_PARAMETER;
  117. goto done;
  118. }
  119. if ((ioOffset | ioLength) & (diskExtension->BiosParameters.BytesPerSector - 1)) {
  120. status = STATUS_INVALID_PARAMETER;
  121. goto done;
  122. }
  123. if ((ioOffset + ioLength) > (diskExtension->BootParameters.PageCount * PAGE_SIZE)) {
  124. status = STATUS_NONEXISTENT_SECTOR;
  125. goto done;
  126. }
  127. if (irpSp->MajorFunction == IRP_MJ_WRITE && diskExtension->BootParameters.ReadOnly) {
  128. status = STATUS_MEDIA_WRITE_PROTECTED;
  129. goto done;
  130. }
  131. //
  132. // Map the pages in the ROM into system space
  133. //
  134. mappingSize = ADDRESS_AND_SIZE_TO_SPAN_PAGES (ioOffset, ioLength) * PAGE_SIZE;
  135. //
  136. // Get a system-space pointer to the disk region.
  137. //
  138. physicalAddress.QuadPart = (diskExtension->BootParameters.BasePage + (ioOffset/PAGE_SIZE)) * PAGE_SIZE;
  139. romPageAddress = MmMapIoSpace(physicalAddress, mappingSize, MmCached);
  140. if (! romPageAddress) {
  141. status = STATUS_INSUFFICIENT_RESOURCES;
  142. goto done;
  143. }
  144. diskByteAddress = romPageAddress + (ioOffset & (PAGE_SIZE-1));
  145. //
  146. // Get a system-space pointer to the user's buffer. A system
  147. // address must be used because we may already have left the
  148. // original caller's address space.
  149. //
  150. Irp->IoStatus.Information = irpSp->Parameters.Read.Length;
  151. ASSERT (Irp->MdlAddress != NULL);
  152. bufferAddress = MmGetSystemAddressForMdlSafe( Irp->MdlAddress, NormalPagePriority );
  153. if (! bufferAddress) {
  154. status = STATUS_INSUFFICIENT_RESOURCES;
  155. goto done;
  156. }
  157. status = STATUS_SUCCESS;
  158. switch (irpSp->MajorFunction) {
  159. case IRP_MJ_READ:
  160. RtlCopyMemory( bufferAddress, diskByteAddress, ioLength );
  161. break;
  162. case IRP_MJ_WRITE:
  163. RtlCopyMemory( diskByteAddress, bufferAddress, ioLength );
  164. break;
  165. default:
  166. ASSERT(FALSE);
  167. status = STATUS_INVALID_PARAMETER;
  168. }
  169. done:
  170. if (romPageAddress) {
  171. MmUnmapIoSpace (romPageAddress, mappingSize);
  172. }
  173. Irp->IoStatus.Status = status;
  174. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  175. return status;
  176. }
  177. NTSTATUS
  178. XIPDiskDeviceControl(
  179. IN PDEVICE_OBJECT DeviceObject,
  180. IN PIRP Irp
  181. )
  182. /*++
  183. Routine Description:
  184. This routine is called by the I/O system to perform a device I/O
  185. control function.
  186. Arguments:
  187. DeviceObject - a pointer to the object that represents the device
  188. that I/O is to be done on.
  189. Irp - a pointer to the I/O Request Packet for this request.
  190. Return Value:
  191. STATUS_SUCCESS if recognized I/O control code,
  192. STATUS_INVALID_DEVICE_REQUEST otherwise.
  193. --*/
  194. {
  195. PBIOS_PARAMETER_BLOCK bios;
  196. PXIPDISK_EXTENSION diskExtension;
  197. PIO_STACK_LOCATION irpSp;
  198. NTSTATUS status;
  199. ULONG info;
  200. //
  201. // Set up necessary object and extension pointers.
  202. //
  203. diskExtension = DeviceObject->DeviceExtension;
  204. bios = &diskExtension->BiosParameters;
  205. irpSp = IoGetCurrentIrpStackLocation( Irp );
  206. //
  207. // Assume failure.
  208. //
  209. status = STATUS_INVALID_DEVICE_REQUEST;
  210. info = 0;
  211. //
  212. // Determine which I/O control code was specified.
  213. //
  214. switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
  215. case IOCTL_DISK_GET_MEDIA_TYPES:
  216. case IOCTL_STORAGE_GET_MEDIA_TYPES:
  217. case IOCTL_DISK_GET_DRIVE_GEOMETRY:
  218. //
  219. // Return the drive geometry for the virtual disk. Note that
  220. // we return values which were made up to suit the disk size.
  221. //
  222. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY)) {
  223. status = STATUS_INVALID_PARAMETER;
  224. } else {
  225. PDISK_GEOMETRY outputBuffer;
  226. outputBuffer = (PDISK_GEOMETRY) Irp->AssociatedIrp.SystemBuffer;
  227. outputBuffer->MediaType = FixedMedia;
  228. outputBuffer->Cylinders.QuadPart = diskExtension->NumberOfCylinders;
  229. outputBuffer->TracksPerCylinder = diskExtension->TracksPerCylinder;
  230. outputBuffer->SectorsPerTrack = bios->SectorsPerTrack;
  231. outputBuffer->BytesPerSector = bios->BytesPerSector;
  232. status = STATUS_SUCCESS;
  233. info = sizeof( DISK_GEOMETRY );
  234. }
  235. break;
  236. #if 0
  237. //
  238. // Ignore these IOCTLs for now.
  239. //
  240. case IOCTL_DISK_SET_PARTITION_INFO:
  241. case IOCTL_DISK_SET_DRIVE_LAYOUT:
  242. status = STATUS_SUCCESS;
  243. break;
  244. #endif
  245. case IOCTL_DISK_GET_PARTITION_INFO:
  246. //
  247. // Return the information about the partition.
  248. //
  249. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(PARTITION_INFORMATION)) {
  250. status = STATUS_INVALID_PARAMETER;
  251. } else {
  252. PPARTITION_INFORMATION outputBuffer;
  253. outputBuffer = (PPARTITION_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
  254. //
  255. // Fat hardwired here...
  256. //
  257. outputBuffer->PartitionType = PARTITION_FAT_16;
  258. outputBuffer->BootIndicator = diskExtension->BootParameters.SystemDrive;
  259. outputBuffer->RecognizedPartition = TRUE;
  260. outputBuffer->RewritePartition = FALSE;
  261. outputBuffer->StartingOffset.QuadPart = 0;
  262. outputBuffer->PartitionLength.QuadPart = diskExtension->BootParameters.PageCount * PAGE_SIZE;
  263. outputBuffer->HiddenSectors = diskExtension->BiosParameters.HiddenSectors;
  264. status = STATUS_SUCCESS;
  265. info = sizeof(PARTITION_INFORMATION);
  266. }
  267. break;
  268. case IOCTL_DISK_VERIFY:
  269. {
  270. PVERIFY_INFORMATION verifyInformation;
  271. ULONG buflen;
  272. ULONG_PTR ioOffset;
  273. ULONG ioLength;
  274. buflen = irpSp->Parameters.DeviceIoControl.InputBufferLength;
  275. if ( buflen < sizeof(VERIFY_INFORMATION) ) {
  276. status = STATUS_INVALID_PARAMETER;
  277. break;
  278. }
  279. verifyInformation = Irp->AssociatedIrp.SystemBuffer;
  280. if (verifyInformation->StartingOffset.HighPart) {
  281. status = STATUS_DISK_CORRUPT_ERROR;
  282. break;
  283. }
  284. ioOffset = verifyInformation->StartingOffset.LowPart;
  285. ioLength = verifyInformation->Length;
  286. if (ioLength == 0) {
  287. status = STATUS_SUCCESS;
  288. } else if ((ioOffset | ioLength) & (diskExtension->BiosParameters.BytesPerSector - 1)) {
  289. status = STATUS_INVALID_PARAMETER;
  290. } else if ((ioOffset + ioLength) > (diskExtension->BootParameters.PageCount * PAGE_SIZE)) {
  291. status = STATUS_NONEXISTENT_SECTOR;
  292. } else {
  293. status = STATUS_SUCCESS;
  294. }
  295. break;
  296. }
  297. case IOCTL_DISK_IS_WRITABLE:
  298. status = diskExtension->BootParameters.ReadOnly? STATUS_MEDIA_WRITE_PROTECTED : STATUS_SUCCESS;
  299. break;
  300. case IOCTL_DISK_CHECK_VERIFY:
  301. case IOCTL_STORAGE_CHECK_VERIFY:
  302. case IOCTL_STORAGE_CHECK_VERIFY2:
  303. status = STATUS_SUCCESS;
  304. break;
  305. default:
  306. //
  307. // The specified I/O control code is unrecognized by this driver.
  308. // The I/O status field in the IRP has already been set so just
  309. // terminate the switch.
  310. //
  311. #if DBG
  312. DbgPrint("XIPDisk: ERROR: unrecognized IOCTL %x\n",
  313. irpSp->Parameters.DeviceIoControl.IoControlCode);
  314. #endif
  315. break;
  316. case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME:
  317. {
  318. PMOUNTDEV_NAME mountName;
  319. ULONG outlen;
  320. outlen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  321. if ( outlen < sizeof(MOUNTDEV_NAME) ) {
  322. status = STATUS_INVALID_PARAMETER;
  323. break;
  324. }
  325. mountName = Irp->AssociatedIrp.SystemBuffer;
  326. mountName->NameLength = diskExtension->DeviceName.Length;
  327. if ( outlen < mountName->NameLength + sizeof(WCHAR)) {
  328. status = STATUS_BUFFER_OVERFLOW;
  329. info = sizeof(MOUNTDEV_NAME);
  330. break;
  331. }
  332. RtlCopyMemory( mountName->Name, diskExtension->DeviceName.Buffer, mountName->NameLength);
  333. status = STATUS_SUCCESS;
  334. info = mountName->NameLength + sizeof(WCHAR);
  335. break;
  336. }
  337. case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID:
  338. {
  339. PMOUNTDEV_UNIQUE_ID uniqueId;
  340. ULONG outlen;
  341. outlen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  342. if (outlen < sizeof(MOUNTDEV_UNIQUE_ID)) {
  343. status = STATUS_INVALID_PARAMETER;
  344. break;
  345. }
  346. uniqueId = Irp->AssociatedIrp.SystemBuffer;
  347. uniqueId->UniqueIdLength = sizeof(XIPDISK_DEVICENAME);
  348. if (outlen < uniqueId->UniqueIdLength) {
  349. status = STATUS_BUFFER_OVERFLOW;
  350. info = sizeof(MOUNTDEV_UNIQUE_ID);
  351. break;
  352. }
  353. RtlCopyMemory( uniqueId->UniqueId, XIPDISK_DEVICENAME, uniqueId->UniqueIdLength );
  354. status = STATUS_SUCCESS;
  355. info = uniqueId->UniqueIdLength;
  356. break;
  357. }
  358. case IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME:
  359. {
  360. status = STATUS_INVALID_DEVICE_REQUEST;
  361. break;
  362. }
  363. }
  364. //
  365. // Finish the I/O operation by simply completing the packet and returning
  366. // the same status as in the packet itself.
  367. // Note that IoCompleteRequest may deallocate Irp before returning.
  368. //
  369. Irp->IoStatus.Information = info;
  370. Irp->IoStatus.Status = status;
  371. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  372. return status;
  373. }
  374. VOID
  375. XIPDiskUnloadDriver(
  376. IN PDRIVER_OBJECT DriverObject
  377. )
  378. /*++
  379. Routine Description:
  380. This routine is called by the I/O system to unload the driver.
  381. Any resources previously allocated must be freed.
  382. Arguments:
  383. DriverObject - a pointer to the object that represents our driver.
  384. Return Value:
  385. None
  386. --*/
  387. {
  388. PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject;
  389. PXIPDISK_EXTENSION diskExtension = deviceObject->DeviceExtension;
  390. RtlFreeUnicodeString(&diskExtension->InterfaceString);
  391. diskExtension->InterfaceString.Buffer = NULL;
  392. if (deviceObject != NULL) {
  393. IoDeleteDevice( deviceObject );
  394. }
  395. }
  396. NTSTATUS
  397. DriverEntry(
  398. IN OUT PDRIVER_OBJECT DriverObject,
  399. IN PUNICODE_STRING RegistryPath
  400. )
  401. /*++
  402. Routine Description:
  403. This routine is called by the Operating System to initialize the driver.
  404. Arguments:
  405. DriverObject - a pointer to a device extension object for the XIPDisk driver.
  406. RegistryPath - a pointer to our Services key in the registry.
  407. Return Value:
  408. STATUS_SUCCESS if this disk is initialized; an error otherwise.
  409. --*/
  410. {
  411. XIP_BOOT_PARAMETERS xipbootparameters;
  412. PBIOS_PARAMETER_BLOCK bios;
  413. NTSTATUS status;
  414. // UNICODE_STRING deviceName;
  415. UNICODE_STRING realDeviceName;
  416. UNICODE_STRING dosSymlink;
  417. UNICODE_STRING driveLetter;
  418. PDEVICE_OBJECT pdo = NULL;
  419. PDEVICE_OBJECT deviceObject;
  420. PXIPDISK_EXTENSION ext = NULL; // ptr to device extension
  421. //
  422. // Read the parameters from the registry
  423. //
  424. status = XIPDispatch(XIPCMD_GETBOOTPARAMETERS, &xipbootparameters, sizeof(xipbootparameters));
  425. if (!NT_SUCCESS(status)) {
  426. return status;
  427. }
  428. if (xipbootparameters.BasePage == 0) {
  429. return STATUS_NO_SUCH_DEVICE;
  430. }
  431. // Initialize the driver object with this driver's entry points.
  432. //
  433. DriverObject->MajorFunction[IRP_MJ_CREATE] = XIPDiskCreateClose;
  434. DriverObject->MajorFunction[IRP_MJ_CLOSE] = XIPDiskCreateClose;
  435. DriverObject->MajorFunction[IRP_MJ_READ] = XIPDiskReadWrite;
  436. DriverObject->MajorFunction[IRP_MJ_WRITE] = XIPDiskReadWrite;
  437. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = XIPDiskDeviceControl;
  438. //
  439. // Create and initialize a device object for the disk.
  440. //
  441. ObReferenceObject(DriverObject);
  442. status = IoReportDetectedDevice(
  443. DriverObject,
  444. InterfaceTypeUndefined,
  445. -1,
  446. -1,
  447. NULL,
  448. NULL,
  449. TRUE,
  450. &pdo
  451. );
  452. if (!NT_SUCCESS(status)) {
  453. return status;
  454. }
  455. //
  456. // Create the XIP root device.
  457. //
  458. RtlInitUnicodeString(&realDeviceName, XIPDISK_DEVICENAME);
  459. status = IoCreateDevice( DriverObject,
  460. sizeof( XIPDISK_EXTENSION ),
  461. &realDeviceName,
  462. FILE_DEVICE_VIRTUAL_DISK,
  463. 0,
  464. FALSE,
  465. &deviceObject );
  466. if (!NT_SUCCESS(status)) {
  467. return status;
  468. }
  469. // ISSUE-2000/10/14-DavePr -- Hardwiring the driveLetter because I haven't
  470. // figured out how to get the mountmgr to give out a drive letter. Naming
  471. // it as a form of floppy (deviceName) was one suggestion that failed (so far).
  472. // The dosSymlink isn't really necessary, but is another
  473. //
  474. // Create symbolic links. Ignore failures
  475. //
  476. // RtlInitUnicodeString(&deviceName, XIPDISK_FLOPPYNAME);
  477. RtlInitUnicodeString(&dosSymlink, XIPDISK_DOSNAME);
  478. RtlInitUnicodeString(&driveLetter, XIPDISK_DRIVELETTER);
  479. // (void) IoCreateSymbolicLink(&deviceName, &realDeviceName);
  480. (void) IoCreateSymbolicLink(&dosSymlink, &realDeviceName);
  481. (void) IoCreateSymbolicLink(&driveLetter, &realDeviceName);
  482. //
  483. // Initialize device object and extension.
  484. //
  485. deviceObject->Flags |= DO_DIRECT_IO | DO_XIP;
  486. deviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
  487. ext = deviceObject->DeviceExtension;
  488. bios = &ext->BiosParameters;
  489. //
  490. // Initialize the newly allocated disk extension from our temporary
  491. // Get the bios boot parameters from the kernel
  492. //
  493. ext->BootParameters = xipbootparameters;
  494. status = XIPDispatch(XIPCMD_GETBIOSPARAMETERS, bios, sizeof(*bios));
  495. //
  496. // Fill in the device objects
  497. //
  498. ext->DeviceObject = deviceObject;
  499. // ext->DeviceName = deviceName;
  500. ext->DeviceName = realDeviceName;
  501. ext->TracksPerCylinder = 1;
  502. ext->BytesPerCylinder = bios->BytesPerSector * bios->SectorsPerTrack * ext->TracksPerCylinder;
  503. ext->NumberOfCylinders = ext->BootParameters.PageCount * PAGE_SIZE / ext->BytesPerCylinder;
  504. //
  505. // Attach the root device
  506. //
  507. ext->TargetObject = IoAttachDeviceToDeviceStack(deviceObject, pdo);
  508. if (!ext->TargetObject) {
  509. // IoDeleteSymbolicLink(&deviceName);
  510. IoDeleteSymbolicLink(&dosSymlink);
  511. IoDeleteSymbolicLink(&driveLetter);
  512. IoDeleteSymbolicLink(&realDeviceName);
  513. IoDeleteDevice(deviceObject);
  514. return STATUS_NO_SUCH_DEVICE;
  515. }
  516. ext->UnderlyingPDO = pdo;
  517. status = IoRegisterDeviceInterface(pdo,
  518. (LPGUID)&DiskClassGuid,
  519. NULL,
  520. &ext->InterfaceString );
  521. if (NT_SUCCESS(status)) {
  522. status = IoSetDeviceInterfaceState( &ext->InterfaceString, TRUE );
  523. if (!NT_SUCCESS(status)) {
  524. DbgPrint("XIP: Warning: ignored failure %x retruned by IoSetDeviceInterface\n", status);
  525. }
  526. } else {
  527. DbgPrint("XIP: Warning: ignored failure %x retruned by IoRegisterDeviceInterface\n", status);
  528. }
  529. return STATUS_SUCCESS;
  530. }