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.

648 lines
12 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. miscsvc.c
  5. Abstract:
  6. This module contains miscellaneous SPUD services.
  7. Author:
  8. Keith Moore (keithmo) 09-Feb-1998
  9. Revision History:
  10. --*/
  11. #include "spudp.h"
  12. //
  13. // Private prototypes.
  14. //
  15. NTSTATUS
  16. SpudpOpenSelfHandle(
  17. OUT PHANDLE SelfHandle
  18. );
  19. NTSTATUS
  20. SpudpCloseSelfHandle(
  21. IN HANDLE SelfHandle
  22. );
  23. NTSTATUS
  24. SpudpInitCompletionPort(
  25. IN HANDLE CompletionPort
  26. );
  27. #ifdef ALLOC_PRAGMA
  28. #pragma alloc_text( PAGE, SPUDInitialize )
  29. #pragma alloc_text( PAGE, SPUDTerminate )
  30. #pragma alloc_text( PAGE, SPUDCancel )
  31. #pragma alloc_text( PAGE, SPUDGetCounts )
  32. #pragma alloc_text( PAGE, SpudpOpenSelfHandle )
  33. #pragma alloc_text( PAGE, SpudpCloseSelfHandle )
  34. #endif
  35. #if 0
  36. NOT PAGEABLE -- SpudpInitCompletionPort
  37. #endif
  38. //
  39. // Public functions.
  40. //
  41. NTSTATUS
  42. SPUDInitialize(
  43. ULONG Version,
  44. HANDLE hPort
  45. )
  46. /*++
  47. Routine Description:
  48. Performs per-process SPUD initialization.
  49. Arguments:
  50. Version - The SPUD interface version the user-mode client is expecting.
  51. hPort - The handle to the user-mode code's I/O completion port.
  52. Return Value:
  53. NTSTATUS - Completion status.
  54. --*/
  55. {
  56. NTSTATUS status;
  57. HANDLE selfHandle;
  58. //
  59. // Sanity check.
  60. //
  61. PAGED_CODE();
  62. status = SPUD_ENTER_SERVICE( "SPUDInitialize", FALSE );
  63. if( !NT_SUCCESS(status) ) {
  64. return status;
  65. }
  66. //
  67. // Setup locals so we know how to cleanup on exit.
  68. //
  69. selfHandle = NULL;
  70. //
  71. // SPUD doesn't support kernel-mode callers. In fact, we don't
  72. // even build the "system stubs" necessary to invoke SPUD from
  73. // kernel-mode.
  74. //
  75. ASSERT( ExGetPreviousMode() == UserMode );
  76. //
  77. // Ensure we got the SPUD interface version number we're expecting.
  78. //
  79. if( Version != SPUD_VERSION ) {
  80. status = STATUS_INVALID_PARAMETER;
  81. }
  82. //
  83. // Open an exclusive handle to ourselves.
  84. //
  85. if( NT_SUCCESS(status) ) {
  86. status = SpudpOpenSelfHandle( &selfHandle );
  87. }
  88. //
  89. // Reference the I/O completion port handle so we can use the
  90. // pointer directly in KeInsertQueue().
  91. //
  92. if( NT_SUCCESS(status) ) {
  93. status = SpudpInitCompletionPort( hPort );
  94. }
  95. //
  96. // Remember that we're initialized.
  97. //
  98. if( NT_SUCCESS(status) ) {
  99. SpudSelfHandle = selfHandle;
  100. } else {
  101. //
  102. // Fatal error, cleanup our self handle if we managed to
  103. // open it.
  104. //
  105. if( selfHandle != NULL ) {
  106. SpudpCloseSelfHandle( selfHandle );
  107. }
  108. }
  109. SPUD_LEAVE_SERVICE( "SPUDInitialize", status, FALSE );
  110. return status;
  111. } // SPUDInitialize
  112. NTSTATUS
  113. SPUDTerminate(
  114. VOID
  115. )
  116. /*++
  117. Routine Description:
  118. Performs per-process SPUD termination.
  119. Arguments:
  120. None.
  121. Return Value:
  122. NTSTATUS - Completion status.
  123. --*/
  124. {
  125. NTSTATUS status;
  126. //
  127. // Sanity check.
  128. //
  129. PAGED_CODE();
  130. status = SPUD_ENTER_SERVICE( "SPUDTerminate", TRUE );
  131. if( !NT_SUCCESS(status) ) {
  132. return status;
  133. }
  134. //
  135. // SPUD doesn't support kernel-mode callers. In fact, we don't
  136. // even build the "system stubs" necessary to invoke SPUD from
  137. // kernel-mode.
  138. //
  139. ASSERT( ExGetPreviousMode() == UserMode );
  140. //
  141. // Close the handle we opened to ourself. The IRP_MJ_CLOSE handler
  142. // will dereference the completion port and reset the global variables.
  143. //
  144. ASSERT( SpudSelfHandle != NULL );
  145. SpudpCloseSelfHandle( SpudSelfHandle );
  146. SpudSelfHandle = NULL;
  147. ASSERT( status == STATUS_SUCCESS );
  148. SPUD_LEAVE_SERVICE( "SPUDTerminate", status, FALSE );
  149. return status;
  150. } // SPUDTerminate
  151. NTSTATUS
  152. SPUDCancel(
  153. IN PSPUD_REQ_CONTEXT reqContext
  154. )
  155. /*++
  156. Routine Description:
  157. Cancels an outstanding XxxAndRecv() request.
  158. Arguments:
  159. reqContext - The user-mode context associated with the I/O request.
  160. Return Value:
  161. NTSTATUS - Completion status.
  162. --*/
  163. {
  164. NTSTATUS status;
  165. PSPUD_AFD_REQ_CONTEXT SpudReqContext;
  166. PIRP irp;
  167. //
  168. // Sanity check.
  169. //
  170. PAGED_CODE();
  171. status = SPUD_ENTER_SERVICE( "SPUDCancel", TRUE );
  172. if( !NT_SUCCESS(status) ) {
  173. return status;
  174. }
  175. //
  176. // SPUD doesn't support kernel-mode callers. In fact, we don't
  177. // even build the "system stubs" necessary to invoke SPUD from
  178. // kernel-mode.
  179. //
  180. ASSERT( ExGetPreviousMode() == UserMode );
  181. try {
  182. //
  183. // Make sure we can write to reqContext
  184. //
  185. ProbeForRead(
  186. reqContext,
  187. sizeof(SPUD_REQ_CONTEXT),
  188. sizeof(ULONG)
  189. );
  190. } except(EXCEPTION_EXECUTE_HANDLER) {
  191. status = GetExceptionCode();
  192. }
  193. //
  194. // Get the kernel-mode context from the user-mode context.
  195. //
  196. if( NT_SUCCESS(status) ) {
  197. SpudReqContext = SpudGetRequestContext( reqContext );
  198. if( SpudReqContext == NULL ) {
  199. status = STATUS_INVALID_PARAMETER;
  200. }
  201. }
  202. //
  203. // Snag the IRP from the context & cancel the request.
  204. //
  205. if( NT_SUCCESS(status) ) {
  206. irp = SpudReqContext->Irp;
  207. if (irp) {
  208. IoCancelIrp(irp);
  209. }
  210. }
  211. SPUD_LEAVE_SERVICE( "SPUDCancel", status, FALSE );
  212. return status;
  213. } // SPUDCancel
  214. NTSTATUS
  215. SPUDGetCounts(
  216. PSPUD_COUNTERS UserCounters
  217. )
  218. /*++
  219. Routine Description:
  220. Retrieves the SPUD activity counters.
  221. Arguments:
  222. UserCounters - Receives the counters.
  223. Return Value:
  224. NTSTATUS - Completion status.
  225. --*/
  226. {
  227. NTSTATUS status;
  228. //
  229. // Sanity check.
  230. //
  231. PAGED_CODE();
  232. //
  233. // N.B. We do not perform the usual driver initialization and
  234. // exclusivity checks here. We *want* SPUDGetCounts to be callable
  235. // by processes other than the server.
  236. //
  237. //
  238. // SPUD doesn't support kernel-mode callers. In fact, we don't
  239. // even build the "system stubs" necessary to invoke SPUD from
  240. // kernel-mode.
  241. //
  242. ASSERT( ExGetPreviousMode() == UserMode );
  243. try {
  244. //
  245. // The SpudCounters parameter must be writable.
  246. //
  247. ProbeForWrite( UserCounters, sizeof(*UserCounters), sizeof(ULONG) );
  248. //
  249. // Copy the counters to the user-mode buffer.
  250. //
  251. RtlCopyMemory(
  252. UserCounters,
  253. &SpudCounters,
  254. sizeof(SpudCounters)
  255. );
  256. status = STATUS_SUCCESS;
  257. } except( EXCEPTION_EXECUTE_HANDLER ) {
  258. status = GetExceptionCode();
  259. }
  260. return status;
  261. } // SPUDGetCounts
  262. //
  263. // Private prototypes.
  264. //
  265. NTSTATUS
  266. SpudpOpenSelfHandle(
  267. OUT PHANDLE SelfHandle
  268. )
  269. /*++
  270. Routine Description:
  271. Opens a handle to \Device\Spud and marks it so that it cannot be
  272. closed.
  273. Arguments:
  274. SelfHandle - Pointer to a variable that receives the handle.
  275. Return Value:
  276. NTSTATUS - Completion status.
  277. --*/
  278. {
  279. NTSTATUS status;
  280. HANDLE selfHandle;
  281. UNICODE_STRING deviceName;
  282. OBJECT_ATTRIBUTES objectAttributes;
  283. IO_STATUS_BLOCK ioStatusBlock;
  284. OBJECT_HANDLE_FLAG_INFORMATION handleInfo;
  285. //
  286. // Sanity check.
  287. //
  288. PAGED_CODE();
  289. //
  290. // Open an exclusive handle to ourselves.
  291. //
  292. RtlInitUnicodeString(
  293. &deviceName,
  294. SPUD_DEVICE_NAME
  295. );
  296. InitializeObjectAttributes(
  297. &objectAttributes, // ObjectAttributes
  298. &deviceName, // ObjectName
  299. OBJ_CASE_INSENSITIVE, // Attributes
  300. NULL, // RootDirectory
  301. NULL // SecurityDescriptor
  302. );
  303. status = IoCreateFile(
  304. &selfHandle, // FileHandle
  305. GENERIC_READ // DesiredAccess
  306. | SYNCHRONIZE //
  307. | FILE_READ_ATTRIBUTES, //
  308. &objectAttributes, // ObjectAttributes
  309. &ioStatusBlock, // IoStatusBlock
  310. NULL, // AllocationSize
  311. 0L, // FileAttributes
  312. 0L, // ShareAccess
  313. FILE_OPEN, // Disposition
  314. 0L, // CreateOptions
  315. NULL, // EaBuffer
  316. 0, // EaLength
  317. CreateFileTypeNone, // CreateFileType
  318. NULL, // ExtraCreateParameters
  319. IO_NO_PARAMETER_CHECKING // Options
  320. );
  321. if( !NT_SUCCESS(status) ) {
  322. return status;
  323. }
  324. //
  325. // Mark the handle so that those pesky user-mode applications
  326. // can't close it. While we're at it, make the handle not
  327. // inheritable.
  328. //
  329. handleInfo.ProtectFromClose = TRUE;
  330. handleInfo.Inherit = FALSE;
  331. status = ZwSetInformationObject(
  332. selfHandle, // Handle
  333. ObjectHandleFlagInformation, // ObjectInformationClass
  334. &handleInfo, // ObjectInformation
  335. sizeof(handleInfo) // ObjectInformationLength
  336. );
  337. //
  338. // If all went well, then return the handle to the caller. Otherwise,
  339. // carefully close the handle (avoiding an exception if the user-mode
  340. // code has already closed it).
  341. //
  342. if( NT_SUCCESS(status) ) {
  343. *SelfHandle = selfHandle;
  344. } else {
  345. if( selfHandle != NULL ) {
  346. try {
  347. NtClose( selfHandle );
  348. } except( EXCEPTION_EXECUTE_HANDLER ) {
  349. NOTHING;
  350. }
  351. }
  352. }
  353. return status;
  354. } // SpudpOpenSelfHandle
  355. NTSTATUS
  356. SpudpCloseSelfHandle(
  357. IN HANDLE SelfHandle
  358. )
  359. /*++
  360. Routine Description:
  361. Closes the handle opened by SpudpOpenSelfHandle().
  362. Arguments:
  363. SelfHandle - The handle to close.
  364. Return Value:
  365. NTSTATUS - Completion status.
  366. --*/
  367. {
  368. NTSTATUS status;
  369. OBJECT_HANDLE_FLAG_INFORMATION handleInfo;
  370. //
  371. // Sanity check.
  372. //
  373. PAGED_CODE();
  374. //
  375. // Mark the handle so that we can close it.
  376. //
  377. handleInfo.ProtectFromClose = FALSE;
  378. handleInfo.Inherit = FALSE;
  379. status = ZwSetInformationObject(
  380. SelfHandle, // Handle
  381. ObjectHandleFlagInformation, // ObjectInformationClass
  382. &handleInfo, // ObjectInformation
  383. sizeof(handleInfo) // ObjectInformationLength
  384. );
  385. //
  386. // Carefully close the handle, even if the above APIs failed.
  387. //
  388. try {
  389. status = NtClose( SelfHandle );
  390. } except( EXCEPTION_EXECUTE_HANDLER ) {
  391. status = GetExceptionCode();
  392. }
  393. return status;
  394. } // SpudpCloseSelfHandle
  395. NTSTATUS
  396. SpudpInitCompletionPort(
  397. IN HANDLE CompletionPort
  398. )
  399. /*++
  400. Routine Description:
  401. References the specified completion port and sets our local reference
  402. count.
  403. N.B. This is a separate routine so that SPUDInitialize() can be pageable.
  404. Arguments:
  405. CompletionPort - The completion port handle.
  406. Return Value:
  407. NTSTATUS - Completion status.
  408. --*/
  409. {
  410. NTSTATUS status;
  411. KIRQL oldIrql;
  412. PVOID completionPort;
  413. //
  414. // Reference the I/O completion port handle so we can use the
  415. // pointer directly in KeInsertQueue().
  416. //
  417. status = ObReferenceObjectByHandle(
  418. CompletionPort, // Handle
  419. IO_COMPLETION_MODIFY_STATE, // DesiredAccess
  420. NULL, // ObjectType
  421. UserMode, // AccessMode
  422. &completionPort, // Object
  423. NULL // HandleInformation
  424. );
  425. //
  426. // Remember that we're initialized.
  427. //
  428. if( NT_SUCCESS(status) ) {
  429. TRACE_OB_REFERENCE( completionPort );
  430. KeAcquireSpinLock(
  431. &SpudCompletionPortLock,
  432. &oldIrql
  433. );
  434. ASSERT( SpudCompletionPort == NULL );
  435. ASSERT( SpudCompletionPortRefCount == 0 );
  436. SpudCompletionPort = completionPort;
  437. SpudCompletionPortRefCount = 1;
  438. KeReleaseSpinLock(
  439. &SpudCompletionPortLock,
  440. oldIrql
  441. );
  442. }
  443. return status;
  444. } // SpudpInitCompletionPort