Leaked source code of windows server 2003
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.

1201 lines
34 KiB

  1. /*++
  2. Copyright (c) 1991 - 2001 Microsoft Corporation
  3. Module Name:
  4. ## # ## ### ###### #### ## ## ##### ##### #### #### ##### #####
  5. ## ### ## ### ## ## # ## ## ## ## ## ## ## # ## # ## ## ## ##
  6. ## ### ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
  7. ## # # ## ## ## ## ## ####### ## ## ## ## ## ### ## ## ## ## ##
  8. ### ### ####### ## ## ## ## ## ## ## ## ## ## ## ##### #####
  9. ### ### ## ## ## ## # ## ## ## ## ## ## ## ## ## ## # ## ##
  10. ## ## ## ## ## #### ## ## ##### ##### ##### ## #### ## ##
  11. Abstract:
  12. This module contains functions specfic to the
  13. watchdog device. The logic in this module is not
  14. hardware specific, but is logic that is common
  15. to all hardware implementations.
  16. Author:
  17. Wesley Witt (wesw) 1-Oct-2001
  18. Environment:
  19. Kernel mode only.
  20. Notes:
  21. --*/
  22. #include "internal.h"
  23. NTSTATUS
  24. SaWatchdogDeviceInitialization(
  25. IN PSAPORT_DRIVER_EXTENSION DriverExtension
  26. )
  27. /*++
  28. Routine Description:
  29. This is the NVRAM specific code for driver initialization.
  30. This function is called by SaPortInitialize, which is called by
  31. the NVRAM driver's DriverEntry function.
  32. Arguments:
  33. DriverExtension - Driver extension structure
  34. Return Value:
  35. NT status code.
  36. --*/
  37. {
  38. UNREFERENCED_PARAMETER(DriverExtension);
  39. return STATUS_SUCCESS;
  40. }
  41. NTSTATUS
  42. SaWatchdogIoValidation(
  43. IN PWATCHDOG_DEVICE_EXTENSION DeviceExtension,
  44. IN PIRP Irp,
  45. PIO_STACK_LOCATION IrpSp
  46. )
  47. /*++
  48. Routine Description:
  49. This is the NVRAM specific code for processing
  50. all I/O validation for reads and writes.
  51. Arguments:
  52. DeviceExtension - NVRAM device extension
  53. Irp - Pointer to an IRP structure that describes the requested I/O operation.
  54. IrpSp - Irp stack pointer
  55. Return Value:
  56. NT status code.
  57. --*/
  58. {
  59. UNREFERENCED_PARAMETER(DeviceExtension);
  60. UNREFERENCED_PARAMETER(Irp);
  61. UNREFERENCED_PARAMETER(IrpSp);
  62. return STATUS_NOT_SUPPORTED;
  63. }
  64. NTSTATUS
  65. SaWatchdogShutdownNotification(
  66. IN PWATCHDOG_DEVICE_EXTENSION DeviceExtension,
  67. IN PIRP Irp,
  68. PIO_STACK_LOCATION IrpSp
  69. )
  70. /*++
  71. Routine Description:
  72. This is the NVRAM specific code for processing
  73. the system shutdown notification.
  74. Arguments:
  75. DeviceExtension - NVRAM device extension
  76. Irp - Pointer to an IRP structure that describes the requested I/O operation.
  77. IrpSp - Irp stack pointer
  78. Return Value:
  79. NT status code.
  80. --*/
  81. {
  82. UNREFERENCED_PARAMETER(DeviceExtension);
  83. UNREFERENCED_PARAMETER(Irp);
  84. UNREFERENCED_PARAMETER(IrpSp);
  85. return STATUS_SUCCESS;
  86. }
  87. VOID
  88. WatchdogProcessPingThread(
  89. IN PVOID StartContext
  90. )
  91. /*++
  92. Routine Description:
  93. This function runs as a system thread and serves to
  94. ping the watchdog hardware while the system boots.
  95. Arguments:
  96. StartContext - Context pointer; device extension
  97. Return Value:
  98. None.
  99. --*/
  100. {
  101. PWATCHDOG_DEVICE_EXTENSION DeviceExtension = (PWATCHDOG_DEVICE_EXTENSION) StartContext;
  102. NTSTATUS Status;
  103. LARGE_INTEGER DueTime;
  104. UNICODE_STRING UnicodeString;
  105. PFILE_OBJECT DisplayFileObject = NULL;
  106. PDEVICE_OBJECT DisplayDeviceObject = NULL;
  107. BOOLEAN BusyMessageDisplayed = FALSE;
  108. ULONG TimerValue = WATCHDOG_TIMER_VALUE;
  109. //
  110. // Set the timer resolution
  111. //
  112. Status = CallMiniPortDriverDeviceControl(
  113. DeviceExtension,
  114. DeviceExtension->DeviceObject,
  115. IOCTL_SAWD_SET_TIMER,
  116. &TimerValue,
  117. sizeof(ULONG),
  118. NULL,
  119. 0
  120. );
  121. if (!NT_SUCCESS(Status)) {
  122. REPORT_ERROR( DeviceExtension->DeviceType, "Failed to ping the watchdog\n", Status );
  123. }
  124. //
  125. // Ping loop
  126. //
  127. while (1) {
  128. //
  129. // Get a pointer to the display device
  130. //
  131. if (DisplayDeviceObject == NULL) {
  132. RtlInitUnicodeString( &UnicodeString, SA_DEVICE_DISPLAY_NAME_STRING );
  133. Status = IoGetDeviceObjectPointer(
  134. &UnicodeString,
  135. FILE_ALL_ACCESS,
  136. &DisplayFileObject,
  137. &DisplayDeviceObject
  138. );
  139. if (!NT_SUCCESS(Status)) {
  140. REPORT_ERROR( DeviceExtension->DeviceType, "IoGetDeviceObjectPointer failed", Status );
  141. }
  142. }
  143. //
  144. // Display the busy message if necessary
  145. //
  146. if (DisplayDeviceObject && BusyMessageDisplayed == FALSE) {
  147. Status = CallMiniPortDriverDeviceControl(
  148. DeviceExtension,
  149. DisplayDeviceObject,
  150. IOCTL_SADISPLAY_BUSY_MESSAGE,
  151. NULL,
  152. 0,
  153. NULL,
  154. 0
  155. );
  156. if (!NT_SUCCESS(Status)) {
  157. REPORT_ERROR( DeviceExtension->DeviceType, "Failed to display the busy message", Status );
  158. } else {
  159. BusyMessageDisplayed = TRUE;
  160. ObDereferenceObject( DisplayFileObject );
  161. }
  162. }
  163. //
  164. // Call the watchdog driver so that the hardware is pinged
  165. // and prevent the system from rebooting
  166. //
  167. Status = CallMiniPortDriverDeviceControl(
  168. DeviceExtension,
  169. DeviceExtension->DeviceObject,
  170. IOCTL_SAWD_PING,
  171. NULL,
  172. 0,
  173. NULL,
  174. 0
  175. );
  176. if (!NT_SUCCESS(Status)) {
  177. REPORT_ERROR( DeviceExtension->DeviceType, "Failed to ping the watchdog\n", Status );
  178. }
  179. //
  180. // Wait...
  181. //
  182. DueTime.QuadPart = -SecToNano(WATCHDOG_PING_SECONDS);
  183. Status = KeWaitForSingleObject( &DeviceExtension->PingEvent, Executive, KernelMode, FALSE, &DueTime );
  184. if (Status != STATUS_TIMEOUT) {
  185. //
  186. // The ping event was triggered
  187. //
  188. //
  189. // Call the watchdog driver so that the hardware is pinged
  190. // and prevent the system from rebooting
  191. //
  192. Status = CallMiniPortDriverDeviceControl(
  193. DeviceExtension,
  194. DeviceExtension->DeviceObject,
  195. IOCTL_SAWD_PING,
  196. NULL,
  197. 0,
  198. NULL,
  199. 0
  200. );
  201. if (!NT_SUCCESS(Status)) {
  202. REPORT_ERROR( DeviceExtension->DeviceType, "Failed to ping the watchdog\n", Status );
  203. }
  204. return;
  205. } else {
  206. //
  207. // We timed out
  208. //
  209. ExAcquireFastMutex( &DeviceExtension->DeviceLock );
  210. if (DeviceExtension->ActiveProcessCount == 0) {
  211. KeQuerySystemTime( &DueTime );
  212. DueTime.QuadPart = NanoToSec( DueTime.QuadPart - DeviceExtension->LastProcessTime.QuadPart );
  213. if (DueTime.QuadPart > WATCHDOG_INIT_SECONDS) {
  214. ExReleaseFastMutex( &DeviceExtension->DeviceLock );
  215. return;
  216. }
  217. }
  218. ExReleaseFastMutex( &DeviceExtension->DeviceLock );
  219. }
  220. }
  221. }
  222. VOID
  223. WatchdogProcessWatchThread(
  224. IN PVOID StartContext
  225. )
  226. /*++
  227. Routine Description:
  228. This function runs as a system thread and the sole
  229. purpose is to wait for a list of processes to terminate.
  230. Arguments:
  231. StartContext - Context pointer; device extension
  232. Return Value:
  233. None.
  234. --*/
  235. {
  236. PWATCHDOG_PROCESS_WATCH ProcessWatch = (PWATCHDOG_PROCESS_WATCH) StartContext;
  237. PWATCHDOG_DEVICE_EXTENSION DeviceExtension = ProcessWatch->DeviceExtension;
  238. NTSTATUS Status;
  239. OBJECT_ATTRIBUTES Obja;
  240. CLIENT_ID ClientId;
  241. HANDLE ProcessHandle = NULL;
  242. LARGE_INTEGER CurrentTime;
  243. __try {
  244. InitializeObjectAttributes( &Obja, NULL, 0, NULL, NULL );
  245. ClientId.UniqueThread = NULL;
  246. ClientId.UniqueProcess = ProcessWatch->ProcessId;
  247. Status = ZwOpenProcess(
  248. &ProcessHandle,
  249. PROCESS_ALL_ACCESS,
  250. &Obja,
  251. &ClientId
  252. );
  253. if (!NT_SUCCESS(Status)) {
  254. ERROR_RETURN( DeviceExtension->DeviceType, "ZwOpenProcess failed", Status );
  255. }
  256. //
  257. // Wait for the process to complete
  258. //
  259. Status = ZwWaitForSingleObject(
  260. ProcessHandle,
  261. FALSE,
  262. NULL
  263. );
  264. if (!NT_SUCCESS(Status)) {
  265. REPORT_ERROR( DeviceExtension->DeviceType, "KeWaitForSingleObject failed", Status );
  266. }
  267. //
  268. // The process terminated
  269. //
  270. ExAcquireFastMutex( &DeviceExtension->DeviceLock );
  271. DeviceExtension->ActiveProcessCount -= 1;
  272. if (DeviceExtension->ActiveProcessCount == 0) {
  273. KeQuerySystemTime( &CurrentTime );
  274. CurrentTime.QuadPart = CurrentTime.QuadPart - DeviceExtension->LastProcessTime.QuadPart;
  275. if (NanoToSec(CurrentTime.QuadPart) > WATCHDOG_INIT_SECONDS) {
  276. KeSetEvent( &DeviceExtension->PingEvent, 0, FALSE );
  277. }
  278. }
  279. ExReleaseFastMutex( &DeviceExtension->DeviceLock );
  280. } __finally {
  281. if (ProcessHandle != NULL) {
  282. ZwClose( ProcessHandle );
  283. }
  284. ExFreePool( ProcessWatch );
  285. }
  286. }
  287. VOID
  288. WatchdogInitializeThread(
  289. IN PVOID StartContext
  290. )
  291. /*++
  292. Routine Description:
  293. This function runs as a system thread and serves to
  294. look for a list of processes running on the system.
  295. Arguments:
  296. StartContext - Context pointer; device extension
  297. Return Value:
  298. None.
  299. --*/
  300. {
  301. PWATCHDOG_DEVICE_EXTENSION DeviceExtension = (PWATCHDOG_DEVICE_EXTENSION) StartContext;
  302. NTSTATUS Status;
  303. ULONG BufferSize;
  304. PUCHAR Buffer = NULL;
  305. PSYSTEM_PROCESS_INFORMATION ProcessInfo;
  306. ULONG TotalOffset;
  307. ULONG TaskBufferSize = 0;
  308. PKEY_VALUE_FULL_INFORMATION KeyInformation = NULL;
  309. PUCHAR p;
  310. ULONG TaskCount = 0;
  311. OBJECT_ATTRIBUTES Obja;
  312. HANDLE ThreadHandle;
  313. LARGE_INTEGER DueTime;
  314. UNICODE_STRING ProcessName;
  315. PWATCHDOG_PROCESS_WATCH ProcessWatch;
  316. PHANDLE Tasks = NULL;
  317. __try {
  318. //
  319. // Read the task names from the registry
  320. //
  321. Status = ReadRegistryValue(
  322. DeviceExtension->DriverExtension,
  323. &DeviceExtension->DriverExtension->RegistryPath,
  324. L"ExceptionTasks",
  325. &KeyInformation
  326. );
  327. if (!NT_SUCCESS(Status)) {
  328. ERROR_RETURN( DeviceExtension->DeviceType, "ReadRegistryValue failed", Status );
  329. }
  330. if (KeyInformation->Type != REG_MULTI_SZ) {
  331. Status = STATUS_OBJECT_TYPE_MISMATCH;
  332. ERROR_RETURN( DeviceExtension->DeviceType, "ExceptionTasks value is corrupt", Status );
  333. }
  334. //
  335. // Count the number of tasks
  336. //
  337. p = (PUCHAR)((PUCHAR)KeyInformation + KeyInformation->DataOffset);
  338. while (*p) {
  339. p += (STRING_SZ(p) + sizeof(WCHAR));
  340. TaskCount += 1;
  341. }
  342. if (TaskCount == 0) {
  343. Status = STATUS_NO_MORE_ENTRIES;
  344. ERROR_RETURN( DeviceExtension->DeviceType, "No tasks specified in the ExceptionTasks registry value", Status );
  345. }
  346. //
  347. // Allocate an array to hold the process handles
  348. //
  349. Tasks = (PHANDLE) ExAllocatePool( NonPagedPool, (TaskCount + 1) * sizeof(HANDLE) );
  350. if (Tasks == NULL) {
  351. Status = STATUS_INSUFFICIENT_RESOURCES;
  352. ERROR_RETURN( DeviceExtension->DeviceType, "Failed to allocate pool for task array buffer", Status );
  353. }
  354. while (1) {
  355. //
  356. // Query the system for the number of tasks that are running
  357. //
  358. Status = ZwQuerySystemInformation(
  359. SystemProcessInformation,
  360. NULL,
  361. 0,
  362. &BufferSize
  363. );
  364. if (Status != STATUS_INFO_LENGTH_MISMATCH) {
  365. ERROR_RETURN( DeviceExtension->DeviceType, "ZwQuerySystemInformation failed", Status );
  366. }
  367. //
  368. // Allocate the pool to hold that process information
  369. //
  370. Buffer = (PUCHAR) ExAllocatePool( NonPagedPool, BufferSize + 2048 );
  371. if (Buffer == NULL) {
  372. Status = STATUS_INSUFFICIENT_RESOURCES;
  373. ERROR_RETURN( DeviceExtension->DeviceType, "Failed to allocate pool for system information buffer", Status );
  374. }
  375. //
  376. // Get the task list from the system
  377. //
  378. Status = ZwQuerySystemInformation(
  379. SystemProcessInformation,
  380. Buffer,
  381. BufferSize,
  382. NULL
  383. );
  384. if (!NT_SUCCESS(Status)) {
  385. ERROR_RETURN( DeviceExtension->DeviceType, "ZwQuerySystemInformation failed", Status );
  386. }
  387. //
  388. // Loop over each running process and check it
  389. // against the exception process list. If the process
  390. // is specified as an exception process then open a handle
  391. // to the process.
  392. //
  393. TaskCount = 0;
  394. p = (PUCHAR)((PUCHAR)KeyInformation + KeyInformation->DataOffset);
  395. //
  396. // Walk the list of processes in the registry value
  397. //
  398. while (*p) {
  399. //
  400. // Loop initialization
  401. //
  402. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION) Buffer;
  403. TotalOffset = 0;
  404. RtlInitUnicodeString( &ProcessName, (PWSTR)p );
  405. //
  406. // Walk the processes in the system process list
  407. // and try to match each with the selected process
  408. // from the registry.
  409. //
  410. while (1) {
  411. //
  412. // Only valid process names
  413. //
  414. if (ProcessInfo->ImageName.Buffer) {
  415. //
  416. // Compare the process names
  417. //
  418. if (RtlCompareUnicodeString( &ProcessInfo->ImageName, &ProcessName, TRUE ) == 0) {
  419. //
  420. // Check to see if we've already seen the process in
  421. // a previous loop thru thr process list
  422. //
  423. if (Tasks[TaskCount] != ProcessInfo->UniqueProcessId) {
  424. //
  425. // The process matches and is new so set things up so
  426. // that we start watching the process to end
  427. //
  428. Tasks[TaskCount] = ProcessInfo->UniqueProcessId;
  429. ProcessWatch = (PWATCHDOG_PROCESS_WATCH) ExAllocatePool( NonPagedPool, sizeof(WATCHDOG_PROCESS_WATCH) );
  430. if (ProcessWatch == NULL) {
  431. Status = STATUS_INSUFFICIENT_RESOURCES;
  432. ERROR_RETURN( DeviceExtension->DeviceType, "Failed to allocate pool for process watch structure", Status );
  433. }
  434. //
  435. // Start the ping thread iff this is the first being watched
  436. //
  437. ExAcquireFastMutex( &DeviceExtension->DeviceLock );
  438. if (DeviceExtension->ActiveProcessCount == 0) {
  439. InitializeObjectAttributes( &Obja, NULL, OBJ_KERNEL_HANDLE, NULL, NULL );
  440. Status = PsCreateSystemThread( &ThreadHandle, 0, &Obja, 0, NULL, WatchdogProcessPingThread, DeviceExtension );
  441. if (!NT_SUCCESS(Status)) {
  442. ExReleaseFastMutex( &DeviceExtension->DeviceLock );
  443. ERROR_RETURN( DeviceExtension->DeviceType, "PsCreateSystemThread failed", Status );
  444. }
  445. ZwClose( ThreadHandle );
  446. }
  447. KeQuerySystemTime( &DeviceExtension->LastProcessTime );
  448. DeviceExtension->ActiveProcessCount += 1;
  449. ExReleaseFastMutex( &DeviceExtension->DeviceLock );
  450. //
  451. // Start a thread to watch this process
  452. //
  453. ProcessWatch->DeviceExtension = DeviceExtension;
  454. ProcessWatch->ProcessId = ProcessInfo->UniqueProcessId;
  455. InitializeObjectAttributes( &Obja, NULL, OBJ_KERNEL_HANDLE, NULL, NULL );
  456. Status = PsCreateSystemThread( &ThreadHandle, 0, &Obja, 0, NULL, WatchdogProcessWatchThread, ProcessWatch );
  457. if (!NT_SUCCESS(Status)) {
  458. ERROR_RETURN( DeviceExtension->DeviceType, "PsCreateSystemThread failed", Status );
  459. }
  460. ZwClose( ThreadHandle );
  461. }
  462. }
  463. }
  464. //
  465. // Loop to the next process in the system process list
  466. //
  467. if (ProcessInfo->NextEntryOffset == 0) {
  468. break;
  469. }
  470. TotalOffset += ProcessInfo->NextEntryOffset;
  471. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION) &Buffer[TotalOffset];
  472. }
  473. //
  474. // Loop to the next process in the registry list
  475. //
  476. p += (STRING_SZ(p) + sizeof(WCHAR));
  477. TaskCount += 1;
  478. }
  479. //
  480. // Clean up all resources allocated in this loop
  481. //
  482. ExFreePool( Buffer );
  483. Buffer = NULL;
  484. //
  485. // Delay execution before looping again
  486. //
  487. DueTime.QuadPart = -SecToNano(WATCHDOG_INIT_SECONDS);
  488. Status = KeWaitForSingleObject( &DeviceExtension->StopEvent, Executive, KernelMode, FALSE, &DueTime );
  489. if (Status != STATUS_TIMEOUT) {
  490. __leave;
  491. }
  492. }
  493. } __finally {
  494. if (KeyInformation) {
  495. ExFreePool( KeyInformation );
  496. }
  497. if (Buffer) {
  498. ExFreePool( Buffer );
  499. }
  500. if (Tasks) {
  501. ExFreePool( Tasks );
  502. }
  503. }
  504. }
  505. ULONG
  506. IsTextModeSetupRunning(
  507. IN PWATCHDOG_DEVICE_EXTENSION DeviceExtension
  508. )
  509. /*++
  510. Routine Description:
  511. This function checks to see if we are running in
  512. text mode setup.
  513. Arguments:
  514. DeviceExtension - NVRAM device extension
  515. Return Value:
  516. NT status code.
  517. --*/
  518. {
  519. NTSTATUS Status;
  520. OBJECT_ATTRIBUTES Obja;
  521. UNICODE_STRING UnicodeString;
  522. HANDLE SetupKey = NULL;
  523. ULONG TextModeSetupInProgress = 0;
  524. //
  525. // Check to see if we're running in GUI mode setup
  526. //
  527. __try {
  528. RtlInitUnicodeString( &UnicodeString, L"\\Registry\\Machine\\System\\ControlSet001\\Services\\setupdd" );
  529. InitializeObjectAttributes(
  530. &Obja,
  531. &UnicodeString,
  532. OBJ_CASE_INSENSITIVE,
  533. NULL,
  534. NULL
  535. );
  536. Status = ZwOpenKey(
  537. &SetupKey,
  538. KEY_READ,
  539. &Obja
  540. );
  541. if (NT_SUCCESS(Status)) {
  542. TextModeSetupInProgress = 1;
  543. } else {
  544. ERROR_RETURN( DeviceExtension->DeviceType, "ZwOpenKey failed", Status );
  545. }
  546. } __finally {
  547. if (SetupKey) {
  548. ZwClose( SetupKey );
  549. }
  550. }
  551. return TextModeSetupInProgress;
  552. }
  553. ULONG
  554. IsGuiModeSetupRunning(
  555. IN PWATCHDOG_DEVICE_EXTENSION DeviceExtension
  556. )
  557. /*++
  558. Routine Description:
  559. This function checks to see if we are running in
  560. GUI mode setup.
  561. Arguments:
  562. DeviceExtension - NVRAM device extension
  563. Return Value:
  564. NT status code.
  565. --*/
  566. {
  567. NTSTATUS Status;
  568. OBJECT_ATTRIBUTES Obja;
  569. UNICODE_STRING UnicodeString;
  570. HANDLE SetupKey = NULL;
  571. UCHAR KeyInformationBuffer[sizeof(KEY_VALUE_FULL_INFORMATION)+64];
  572. PKEY_VALUE_FULL_INFORMATION KeyInformation = (PKEY_VALUE_FULL_INFORMATION) KeyInformationBuffer;
  573. ULONG KeyValueLength;
  574. ULONG SystemSetupInProgress = 0;
  575. //
  576. // Check to see if we're running in GUI mode setup
  577. //
  578. __try {
  579. RtlInitUnicodeString( &UnicodeString, L"\\Registry\\Machine\\System\\Setup" );
  580. InitializeObjectAttributes(
  581. &Obja,
  582. &UnicodeString,
  583. OBJ_CASE_INSENSITIVE,
  584. NULL,
  585. NULL
  586. );
  587. Status = ZwOpenKey(
  588. &SetupKey,
  589. KEY_READ,
  590. &Obja
  591. );
  592. if (!NT_SUCCESS(Status)) {
  593. ERROR_RETURN( DeviceExtension->DeviceType, "ZwOpenKey failed", Status );
  594. }
  595. RtlInitUnicodeString( &UnicodeString, L"SystemSetupInProgress" );
  596. Status = ZwQueryValueKey(
  597. SetupKey,
  598. &UnicodeString,
  599. KeyValueFullInformation,
  600. KeyInformation,
  601. sizeof(KeyInformationBuffer),
  602. &KeyValueLength
  603. );
  604. if (!NT_SUCCESS(Status)) {
  605. ERROR_RETURN( DeviceExtension->DeviceType, "ZwQueryValueKey failed", Status );
  606. }
  607. if (KeyInformation->Type != REG_DWORD) {
  608. Status = STATUS_OBJECT_TYPE_MISMATCH;
  609. ERROR_RETURN( DeviceExtension->DeviceType, "SystemSetupInProgress value is corrupt", Status );
  610. }
  611. SystemSetupInProgress = *(PULONG)((PUCHAR)KeyInformation + KeyInformation->DataOffset);
  612. } __finally {
  613. if (SetupKey) {
  614. ZwClose( SetupKey );
  615. }
  616. }
  617. return SystemSetupInProgress;
  618. }
  619. NTSTATUS
  620. SaWatchdogStartDevice(
  621. IN PWATCHDOG_DEVICE_EXTENSION DeviceExtension
  622. )
  623. /*++
  624. Routine Description:
  625. This is the NVRAM specific code for processing
  626. the PNP start device request.
  627. Arguments:
  628. DeviceExtension - NVRAM device extension
  629. Return Value:
  630. NT status code.
  631. --*/
  632. {
  633. NTSTATUS Status;
  634. OBJECT_ATTRIBUTES Obja;
  635. HANDLE ThreadHandle;
  636. ULONG SetupInProgress = 0;
  637. //
  638. // Setup the device extension fields
  639. //
  640. ExInitializeFastMutex( &DeviceExtension->DeviceLock );
  641. KeInitializeEvent( &DeviceExtension->PingEvent, SynchronizationEvent, FALSE );
  642. KeInitializeEvent( &DeviceExtension->StopEvent, SynchronizationEvent, FALSE );
  643. //
  644. // Check to see if we're running in setup
  645. //
  646. if (IsTextModeSetupRunning( DeviceExtension ) || IsGuiModeSetupRunning( DeviceExtension )) {
  647. SetupInProgress = 1;
  648. }
  649. if (SetupInProgress != 0) {
  650. //
  651. // Start the ping thread so that setup is not terminated
  652. //
  653. DeviceExtension->ActiveProcessCount += 1;
  654. InitializeObjectAttributes( &Obja, NULL, OBJ_KERNEL_HANDLE, NULL, NULL );
  655. Status = PsCreateSystemThread( &ThreadHandle, 0, &Obja, 0, NULL, WatchdogProcessPingThread, DeviceExtension );
  656. if (!NT_SUCCESS(Status)) {
  657. REPORT_ERROR( DeviceExtension->DeviceType, "PsCreateSystemThread failed", Status );
  658. } else {
  659. ZwClose( ThreadHandle );
  660. }
  661. return STATUS_SUCCESS;
  662. }
  663. //
  664. // Start the delay boot initialization thread
  665. //
  666. InitializeObjectAttributes( &Obja, NULL, OBJ_KERNEL_HANDLE, NULL, NULL );
  667. Status = PsCreateSystemThread( &ThreadHandle, 0, &Obja, 0, NULL, WatchdogInitializeThread, DeviceExtension );
  668. if (!NT_SUCCESS(Status)) {
  669. REPORT_ERROR( DeviceExtension->DeviceType, "PsCreateSystemThread failed", Status );
  670. } else {
  671. ZwClose( ThreadHandle );
  672. }
  673. return STATUS_SUCCESS;
  674. }
  675. DECLARE_IOCTL_HANDLER( HandleWdDisable )
  676. /*++
  677. Routine Description:
  678. This routine allows the watchdog timer to be started or stopped.
  679. Arguments:
  680. DeviceObject - The device object for the target device.
  681. Irp - Pointer to an IRP structure that describes the requested I/O operation.
  682. DeviceExtension - Pointer to the main port driver device extension.
  683. InputBuffer - Pointer to the user's input buffer
  684. InputBufferLength - Length in bytes of the input buffer
  685. OutputBuffer - Pointer to the user's output buffer
  686. OutputBufferLength - Length in bytes of the output buffer
  687. Return Value:
  688. NT status code.
  689. --*/
  690. {
  691. if (InputBufferLength != sizeof(ULONG)) {
  692. REPORT_ERROR( DeviceExtension->DeviceType, "Input buffer != sizeof(ULONG)", STATUS_INVALID_BUFFER_SIZE );
  693. return CompleteRequest( Irp, STATUS_INVALID_BUFFER_SIZE, 0 );
  694. }
  695. return DO_DEFAULT();
  696. }
  697. DECLARE_IOCTL_HANDLER( HandleWdQueryExpireBehavior )
  698. /*++
  699. Routine Description:
  700. This routine queries the watchdog expiry behavior
  701. Arguments:
  702. DeviceObject - The device object for the target device.
  703. Irp - Pointer to an IRP structure that describes the requested I/O operation.
  704. DeviceExtension - Pointer to the main port driver device extension.
  705. InputBuffer - Pointer to the user's input buffer
  706. InputBufferLength - Length in bytes of the input buffer
  707. OutputBuffer - Pointer to the user's output buffer
  708. OutputBufferLength - Length in bytes of the output buffer
  709. Return Value:
  710. NT status code.
  711. --*/
  712. {
  713. if (OutputBufferLength != sizeof(ULONG)) {
  714. REPORT_ERROR( DeviceExtension->DeviceType, "output buffer != sizeof(ULONG)", STATUS_INVALID_BUFFER_SIZE );
  715. return CompleteRequest( Irp, STATUS_INVALID_BUFFER_SIZE, 0 );
  716. }
  717. return DO_DEFAULT();
  718. }
  719. DECLARE_IOCTL_HANDLER( HandleWdSetExpireBehavior )
  720. /*++
  721. Routine Description:
  722. This routine set/changes the watchdog expiry behavior
  723. Arguments:
  724. DeviceObject - The device object for the target device.
  725. Irp - Pointer to an IRP structure that describes the requested I/O operation.
  726. DeviceExtension - Pointer to the main port driver device extension.
  727. InputBuffer - Pointer to the user's input buffer
  728. InputBufferLength - Length in bytes of the input buffer
  729. OutputBuffer - Pointer to the user's output buffer
  730. OutputBufferLength - Length in bytes of the output buffer
  731. Return Value:
  732. NT status code.
  733. --*/
  734. {
  735. if (InputBufferLength != sizeof(ULONG)) {
  736. REPORT_ERROR( DeviceExtension->DeviceType, "Input buffer != sizeof(ULONG)", STATUS_INVALID_BUFFER_SIZE );
  737. return CompleteRequest( Irp, STATUS_INVALID_BUFFER_SIZE, 0 );
  738. }
  739. return DO_DEFAULT();
  740. }
  741. DECLARE_IOCTL_HANDLER( HandleWdPing )
  742. /*++
  743. Routine Description:
  744. This routine pings the watchdog timer to prevent
  745. the timer from expiring and restarting the system.
  746. Arguments:
  747. DeviceObject - The device object for the target device.
  748. Irp - Pointer to an IRP structure that describes the requested I/O operation.
  749. DeviceExtension - Pointer to the main port driver device extension.
  750. InputBuffer - Pointer to the user's input buffer
  751. InputBufferLength - Length in bytes of the input buffer
  752. OutputBuffer - Pointer to the user's output buffer
  753. OutputBufferLength - Length in bytes of the output buffer
  754. Return Value:
  755. NT status code.
  756. --*/
  757. {
  758. if (!IS_IRP_INTERNAL( Irp )) {
  759. KeSetEvent( &((PWATCHDOG_DEVICE_EXTENSION)DeviceExtension)->StopEvent, 0, FALSE );
  760. KeSetEvent( &((PWATCHDOG_DEVICE_EXTENSION)DeviceExtension)->PingEvent, 0, FALSE );
  761. }
  762. return DO_DEFAULT();
  763. }
  764. DECLARE_IOCTL_HANDLER( HandleWdDelayBoot )
  765. /*++
  766. Routine Description:
  767. This routine pings the watchdog timer to prevent
  768. the timer from expiring and restarting the system.
  769. Arguments:
  770. DeviceObject - The device object for the target device.
  771. Irp - Pointer to an IRP structure that describes the requested I/O operation.
  772. DeviceExtension - Pointer to the main port driver device extension.
  773. InputBuffer - Pointer to the user's input buffer
  774. InputBufferLength - Length in bytes of the input buffer
  775. OutputBuffer - Pointer to the user's output buffer
  776. OutputBufferLength - Length in bytes of the output buffer
  777. Return Value:
  778. NT status code.
  779. --*/
  780. {
  781. NTSTATUS Status;
  782. LARGE_INTEGER CurrentTime;
  783. OBJECT_ATTRIBUTES Obja;
  784. HANDLE ThreadHandle;
  785. if (InputBufferLength != sizeof(ULONG)) {
  786. REPORT_ERROR( ((PWATCHDOG_DEVICE_EXTENSION)DeviceExtension)->DeviceType, "Input buffer length != sizeof(ULONG)", STATUS_INVALID_BUFFER_SIZE );
  787. return CompleteRequest( Irp, STATUS_INVALID_BUFFER_SIZE, 0 );
  788. }
  789. ExAcquireFastMutex( &((PWATCHDOG_DEVICE_EXTENSION)DeviceExtension)->DeviceLock );
  790. switch (*((PULONG)InputBuffer)) {
  791. case 0:
  792. //
  793. // Disable the delay boot, meaning that the system should continue booting
  794. //
  795. ((PWATCHDOG_DEVICE_EXTENSION)DeviceExtension)->ActiveProcessCount -= 1;
  796. if (((PWATCHDOG_DEVICE_EXTENSION)DeviceExtension)->ActiveProcessCount == 0) {
  797. KeQuerySystemTime( &CurrentTime );
  798. CurrentTime.QuadPart = CurrentTime.QuadPart - ((PWATCHDOG_DEVICE_EXTENSION)DeviceExtension)->LastProcessTime.QuadPart;
  799. if (NanoToSec(CurrentTime.QuadPart) > WATCHDOG_INIT_SECONDS) {
  800. KeSetEvent( &((PWATCHDOG_DEVICE_EXTENSION)DeviceExtension)->PingEvent, 0, FALSE );
  801. }
  802. }
  803. break;
  804. case 1:
  805. //
  806. // Enable the delay boot, meaning that the system will delay until this driver is finished
  807. //
  808. if (((PWATCHDOG_DEVICE_EXTENSION)DeviceExtension)->ActiveProcessCount == 0) {
  809. InitializeObjectAttributes( &Obja, NULL, OBJ_KERNEL_HANDLE, NULL, NULL );
  810. Status = PsCreateSystemThread( &ThreadHandle, 0, &Obja, 0, NULL, WatchdogProcessPingThread, DeviceExtension );
  811. if (!NT_SUCCESS(Status)) {
  812. REPORT_ERROR( ((PWATCHDOG_DEVICE_EXTENSION)DeviceExtension)->DeviceType, "PsCreateSystemThread failed", Status );
  813. } else {
  814. ZwClose( ThreadHandle );
  815. }
  816. }
  817. ((PWATCHDOG_DEVICE_EXTENSION)DeviceExtension)->ActiveProcessCount += 1;
  818. break;
  819. default:
  820. break;
  821. }
  822. ExReleaseFastMutex( &((PWATCHDOG_DEVICE_EXTENSION)DeviceExtension)->DeviceLock );
  823. return DO_DEFAULT();
  824. }
  825. DECLARE_IOCTL_HANDLER( HandleWdQueryTimer )
  826. /*++
  827. Routine Description:
  828. This routine queries the watchdog timer value. The timer counts
  829. down from a BIOS set value to zero. When the timer reaches zero the
  830. BIOS assumes that the system is non-responsive and the system
  831. is either restarted or shutdown.
  832. Arguments:
  833. DeviceObject - The device object for the target device.
  834. Irp - Pointer to an IRP structure that describes the requested I/O operation.
  835. DeviceExtension - Pointer to the main port driver device extension.
  836. InputBuffer - Pointer to the user's input buffer
  837. InputBufferLength - Length in bytes of the input buffer
  838. OutputBuffer - Pointer to the user's output buffer
  839. OutputBufferLength - Length in bytes of the output buffer
  840. Return Value:
  841. NT status code.
  842. --*/
  843. {
  844. if (OutputBufferLength != sizeof(ULONG)) {
  845. REPORT_ERROR( DeviceExtension->DeviceType, "Output buffer != sizeof(ULONG)", STATUS_INVALID_BUFFER_SIZE );
  846. return CompleteRequest( Irp, STATUS_INVALID_BUFFER_SIZE, 0 );
  847. }
  848. return DO_DEFAULT();
  849. }
  850. DECLARE_IOCTL_HANDLER( HandleWdSetTimer )
  851. /*++
  852. Routine Description:
  853. This routine sets/changes the watchdog timer value. The timer counts
  854. down from a BIOS set value to zero. When the timer reaches zero the
  855. BIOS assumes that the system is non-responsive and the system
  856. is either restarted or shutdown.
  857. Arguments:
  858. DeviceObject - The device object for the target device.
  859. Irp - Pointer to an IRP structure that describes the requested I/O operation.
  860. DeviceExtension - Pointer to the main port driver device extension.
  861. InputBuffer - Pointer to the user's input buffer
  862. InputBufferLength - Length in bytes of the input buffer
  863. OutputBuffer - Pointer to the user's output buffer
  864. OutputBufferLength - Length in bytes of the output buffer
  865. Return Value:
  866. NT status code.
  867. --*/
  868. {
  869. if (InputBufferLength != sizeof(ULONG)) {
  870. REPORT_ERROR( DeviceExtension->DeviceType, "Input buffer != sizeof(ULONG)", STATUS_INVALID_BUFFER_SIZE );
  871. return CompleteRequest( Irp, STATUS_INVALID_BUFFER_SIZE, 0 );
  872. }
  873. return DO_DEFAULT();
  874. }