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.

1487 lines
38 KiB

  1. /*++
  2. Copyright (c) 1991-2001 Microsoft Corporation
  3. Module Name:
  4. erwatch.cpp
  5. Abstract:
  6. This module contains the code to report pending watchdog timeout
  7. events at logon after dirty reboot.
  8. Author:
  9. Michael Maciesowicz (mmacie) 29-May-2001
  10. Environment:
  11. User mode at logon.
  12. Revision History:
  13. --*/
  14. #include "savedump.h"
  15. HANDLE
  16. CreateWatchdogEventFile(
  17. IN PWSTR FileName
  18. )
  19. /*++
  20. Routine Description:
  21. This routine creates watchdog event report file.
  22. Arguments:
  23. FileName - Points to the watchdog event file name.
  24. Return Value:
  25. File handle if successful, INVALID_HANDLE_VALUE otherwise.
  26. --*/
  27. {
  28. WCHAR Buffer[256];
  29. HANDLE FileHandle;
  30. BOOL Status;
  31. SYSTEMTIME Time;
  32. TIME_ZONE_INFORMATION TimeZone;
  33. //
  34. // Create watchdog event file.
  35. //
  36. FileHandle = CreateFile(FileName,
  37. GENERIC_WRITE,
  38. FILE_SHARE_READ,
  39. NULL,
  40. CREATE_ALWAYS,
  41. FILE_ATTRIBUTE_NORMAL,
  42. NULL);
  43. if (INVALID_HANDLE_VALUE == FileHandle)
  44. {
  45. return FileHandle;
  46. }
  47. //
  48. // Write header info.
  49. //
  50. Status = WriteWatchdogEventFile(FileHandle, L"//\r\n// Watchdog Event Log File\r\n//\r\n\r\n");
  51. if (TRUE == Status)
  52. {
  53. Status = WriteWatchdogEventFile(FileHandle, L"LogType: Watchdog\r\n");
  54. }
  55. if (TRUE == Status)
  56. {
  57. GetLocalTime(&Time);
  58. swprintf(Buffer,
  59. L"Created: %d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d\r\n",
  60. Time.wYear,
  61. Time.wMonth,
  62. Time.wDay,
  63. Time.wHour,
  64. Time.wMinute,
  65. Time.wSecond);
  66. Status = WriteWatchdogEventFile(FileHandle, Buffer);
  67. }
  68. if (TRUE == Status)
  69. {
  70. GetTimeZoneInformation(&TimeZone);
  71. swprintf(Buffer,
  72. L"TimeZone: %d - %s\r\n",
  73. TimeZone.Bias,
  74. TimeZone.StandardName);
  75. Status = WriteWatchdogEventFile(FileHandle, Buffer);
  76. }
  77. if (TRUE == Status)
  78. {
  79. swprintf(Buffer, L"WindowsVersion: XP\r\n");
  80. Status = WriteWatchdogEventFile(FileHandle, Buffer);
  81. }
  82. if (TRUE == Status)
  83. {
  84. Status = WriteWatchdogEventFile(FileHandle, L"EventType: 0xEA - Thread Stuck in Device Driver\r\n");
  85. }
  86. if (FALSE == Status)
  87. {
  88. CloseHandle(FileHandle);
  89. FileHandle = INVALID_HANDLE_VALUE;
  90. }
  91. return FileHandle;
  92. }
  93. BOOL
  94. CreateWatchdogEventFileName(
  95. OUT PWSTR FileName
  96. )
  97. /*++
  98. Routine Description:
  99. This routine generates watchdog event report full path file name.
  100. Arguments:
  101. FileName - Points to the storage for generated file name (MAX_PATH
  102. size assumed).
  103. Return Value:
  104. TRUE if successful, FALSE otherwise.
  105. --*/
  106. {
  107. INT Retry;
  108. WCHAR DirName[MAX_PATH];
  109. DWORD Size;
  110. DWORD ReturnedSize;
  111. SYSTEMTIME Time;
  112. ASSERT(NULL != FileName);
  113. //
  114. // Create %SystemRoot%\LogFiles\Watchdog directory for watchdog event files.
  115. //
  116. Size = MAX_PATH - sizeof (L"YYMMDD_HHMM_NN.wdl");
  117. ReturnedSize = ExpandEnvironmentStrings(L"%SystemRoot%\\LogFiles",
  118. DirName,
  119. Size);
  120. if ((0 == ReturnedSize) || (ReturnedSize > Size))
  121. {
  122. return FALSE;
  123. }
  124. CreateDirectory(DirName, NULL);
  125. ReturnedSize = ExpandEnvironmentStrings(L"%SystemRoot%\\LogFiles\\Watchdog",
  126. DirName,
  127. Size);
  128. if ((0 == ReturnedSize) || (ReturnedSize > Size))
  129. {
  130. return FALSE;
  131. }
  132. CreateDirectory(DirName, NULL);
  133. //
  134. // Create watchdog event file as YYMMDD_HHMM_NN.wdl.
  135. //
  136. GetLocalTime(&Time);
  137. for (Retry = 1; Retry < ER_WD_MAX_RETRY; Retry++)
  138. {
  139. swprintf(FileName,
  140. L"%s\\%2.2d%2.2d%2.2d_%2.2d%2.2d_%2.2d.wdl",
  141. DirName,
  142. Time.wYear % 100,
  143. Time.wMonth,
  144. Time.wDay,
  145. Time.wHour,
  146. Time.wMinute,
  147. Retry);
  148. if ((GetFileAttributes(FileName) == (DWORD)-1) &&
  149. (GetLastError() == ERROR_FILE_NOT_FOUND))
  150. {
  151. break;
  152. }
  153. }
  154. //
  155. // If we failed to create a suitable file name just fail.
  156. //
  157. if (Retry == ER_WD_MAX_RETRY)
  158. {
  159. return FALSE;
  160. }
  161. return TRUE;
  162. }
  163. USHORT
  164. GenerateSignature(
  165. OUT PER_WD_PCI_ID PciId,
  166. OUT PER_WD_DRIVER_INFO DriverInfo
  167. )
  168. /*++
  169. Routine Description:
  170. This routine generates unique failure signature for given PCI ID and driver data.
  171. Arguments:
  172. PciId - Points to PCI ID info.
  173. DriverInfo - Points to driver version info.
  174. Return Value:
  175. Failure signature.
  176. --*/
  177. {
  178. USHORT Signature;
  179. PUSHORT DataPtr;
  180. LONG Count;
  181. LONG MaxCount;
  182. Signature = 0;
  183. if ((NULL == PciId) || (NULL == DriverInfo))
  184. {
  185. return Signature;
  186. }
  187. //
  188. // Build word CRC checksum for PciId.
  189. //
  190. MaxCount = sizeof (ER_WD_PCI_ID) / sizeof (USHORT);
  191. DataPtr = (PUSHORT)PciId;
  192. for (Count = 0; Count < MaxCount; Count++)
  193. {
  194. Signature ^= *DataPtr;
  195. DataPtr++;
  196. }
  197. //
  198. // Check for odd byte.
  199. //
  200. if (sizeof (ER_WD_PCI_ID) % sizeof (USHORT))
  201. {
  202. Signature ^= *(PUCHAR)DataPtr;
  203. }
  204. //
  205. // Now append DriverInfo.
  206. //
  207. MaxCount = sizeof (ER_WD_DRIVER_INFO) / sizeof (USHORT);
  208. DataPtr = (PUSHORT)DriverInfo;
  209. for (Count = 0; Count < MaxCount; Count++)
  210. {
  211. Signature ^= *DataPtr;
  212. DataPtr++;
  213. }
  214. //
  215. // Check for odd byte.
  216. //
  217. if (sizeof (ER_WD_DRIVER_INFO) % sizeof (USHORT))
  218. {
  219. Signature ^= *(PUCHAR)DataPtr;
  220. }
  221. return Signature;
  222. }
  223. VOID
  224. GetDriverInfo(
  225. IN HKEY Key,
  226. IN OPTIONAL PWCHAR Extension,
  227. OUT PER_WD_DRIVER_INFO DriverInfo
  228. )
  229. /*++
  230. Routine Description:
  231. This routine collects driver's version info.
  232. Arguments:
  233. Key - Watchdog open key (device specific).
  234. Extension - Driver file name extension if one should be appended.
  235. DriverInfo - Storage for driver version info.
  236. Return Value:
  237. --*/
  238. {
  239. PVOID VersionBuffer;
  240. PVOID VersionValue;
  241. LONG WinStatus;
  242. DWORD Type;
  243. DWORD Handle;
  244. DWORD RegLength;
  245. ULONG Index;
  246. USHORT CodePage;
  247. UINT Length;
  248. if (NULL == DriverInfo)
  249. {
  250. return;
  251. }
  252. ZeroMemory(DriverInfo, sizeof (ER_WD_DRIVER_INFO));
  253. //
  254. // Get driver file name from registry.
  255. //
  256. RegLength = MAX_PATH;
  257. WinStatus = RegQueryValueEx(Key,
  258. L"DriverName",
  259. NULL,
  260. &Type,
  261. (LPBYTE)DriverInfo->DriverName,
  262. &RegLength);
  263. if (ERROR_SUCCESS != WinStatus)
  264. {
  265. swprintf(DriverInfo->DriverName, L"%s", L"Unknown");
  266. return;
  267. }
  268. if (Extension)
  269. {
  270. if ((wcslen(DriverInfo->DriverName) <= wcslen(Extension)) ||
  271. wcscmp(DriverInfo->DriverName + wcslen(DriverInfo->DriverName) - wcslen(Extension), Extension))
  272. {
  273. wcscat(DriverInfo->DriverName, Extension);
  274. }
  275. }
  276. Length = GetFileVersionInfoSize(DriverInfo->DriverName, &Handle);
  277. if (Length)
  278. {
  279. VersionBuffer = malloc(Length);
  280. if (NULL != VersionBuffer)
  281. {
  282. if (GetFileVersionInfo(DriverInfo->DriverName, Handle, Length, VersionBuffer))
  283. {
  284. //
  285. // Get fixed file info.
  286. //
  287. if (VerQueryValue(VersionBuffer,
  288. L"\\",
  289. &VersionValue,
  290. &Length))
  291. {
  292. CopyMemory(&(DriverInfo->FixedFileInfo),
  293. VersionValue,
  294. min(Length, sizeof (VS_FIXEDFILEINFO)));
  295. }
  296. //
  297. // Try to locate English code page.
  298. //
  299. CodePage = 0;
  300. if (VerQueryValue(VersionBuffer,
  301. L"\\VarFileInfo\\Translation",
  302. &VersionValue,
  303. &Length))
  304. {
  305. for (Index = 0; Index < Length / sizeof (ER_WD_LANG_AND_CODE_PAGE); Index++)
  306. {
  307. if (((PER_WD_LANG_AND_CODE_PAGE)VersionValue + Index)->Language == ER_WD_LANG_ENGLISH)
  308. {
  309. CodePage = ((PER_WD_LANG_AND_CODE_PAGE)VersionValue + Index)->CodePage;
  310. break;
  311. }
  312. }
  313. }
  314. if (CodePage)
  315. {
  316. WCHAR ValueName[ER_WD_MAX_NAME_LENGTH + 1];
  317. PWCHAR Destination[] =
  318. {
  319. DriverInfo->Comments,
  320. DriverInfo->CompanyName,
  321. DriverInfo->FileDescription,
  322. DriverInfo->FileVersion,
  323. DriverInfo->InternalName,
  324. DriverInfo->LegalCopyright,
  325. DriverInfo->LegalTrademarks,
  326. DriverInfo->OriginalFilename,
  327. DriverInfo->PrivateBuild,
  328. DriverInfo->ProductName,
  329. DriverInfo->ProductVersion,
  330. DriverInfo->SpecialBuild,
  331. NULL
  332. };
  333. PWCHAR Source[] =
  334. {
  335. L"Comments",
  336. L"CompanyName",
  337. L"FileDescription",
  338. L"FileVersion",
  339. L"InternalName",
  340. L"LegalCopyright",
  341. L"LegalTrademarks",
  342. L"OriginalFilename",
  343. L"PrivateBuild",
  344. L"ProductName",
  345. L"ProductVersion",
  346. L"SpecialBuild",
  347. NULL
  348. };
  349. //
  350. // Read version properties.
  351. //
  352. for (Index = 0; Source[Index] && Destination[Index]; Index++)
  353. {
  354. swprintf(ValueName, L"\\StringFileInfo\\%04X%04X\\%s", ER_WD_LANG_ENGLISH, CodePage, Source[Index]);
  355. if (VerQueryValue(VersionBuffer,
  356. ValueName,
  357. &VersionValue,
  358. &Length))
  359. {
  360. CopyMemory(Destination[Index],
  361. VersionValue,
  362. min(Length * sizeof (WCHAR), ER_WD_MAX_FILE_INFO_LENGTH * sizeof (WCHAR)));
  363. }
  364. }
  365. }
  366. }
  367. free(VersionBuffer);
  368. }
  369. }
  370. }
  371. UCHAR
  372. GetFlags(
  373. IN HKEY Key
  374. )
  375. /*++
  376. Routine Description:
  377. This routine returns error signature flags based on registry
  378. values stored by watchdog.
  379. Arguments:
  380. Key - Watchdog open key (device specific).
  381. Return Value:
  382. --*/
  383. {
  384. UCHAR Flags;
  385. LONG WinStatus;
  386. DWORD Type;
  387. DWORD Value;
  388. DWORD Length;
  389. Flags = 0;
  390. //
  391. // Get watchdog values from registry.
  392. //
  393. Length = sizeof (DWORD);
  394. WinStatus = RegQueryValueEx(Key,
  395. L"DisableBugcheck",
  396. NULL,
  397. &Type,
  398. (LPBYTE)&Value,
  399. &Length);
  400. if ((ERROR_SUCCESS == WinStatus) && Value)
  401. {
  402. Flags |= ER_WD_DISABLE_BUGCHECK_FLAG;
  403. }
  404. Length = sizeof (DWORD);
  405. WinStatus = RegQueryValueEx(Key,
  406. L"DebuggerNotPresent",
  407. NULL,
  408. &Type,
  409. (LPBYTE)&Value,
  410. &Length);
  411. if ((ERROR_SUCCESS == WinStatus) && Value)
  412. {
  413. Flags |= ER_WD_DEBUGGER_NOT_PRESENT_FLAG;
  414. }
  415. Length = sizeof (DWORD);
  416. WinStatus = RegQueryValueEx(Key,
  417. L"BugcheckTriggered",
  418. NULL,
  419. &Type,
  420. (LPBYTE)&Value,
  421. &Length);
  422. if ((ERROR_SUCCESS == WinStatus) && Value)
  423. {
  424. Flags |= ER_WD_BUGCHECK_TRIGGERED_FLAG;
  425. }
  426. return Flags;
  427. }
  428. VOID
  429. GetPciId(
  430. IN HKEY Key,
  431. OUT PER_WD_PCI_ID PciId
  432. )
  433. /*++
  434. Routine Description:
  435. This routine collects PCI ID info.
  436. Arguments:
  437. Key - Watchdog open key (device specific).
  438. PciId - Storage for PCI ID info.
  439. Return Value:
  440. --*/
  441. {
  442. PWCHAR HardwareId;
  443. PWCHAR Token;
  444. PWCHAR EndPointer;
  445. LONG WinStatus;
  446. DWORD Type;
  447. DWORD Length;
  448. if (NULL == PciId)
  449. {
  450. return;
  451. }
  452. ZeroMemory(PciId, sizeof (ER_WD_PCI_ID));
  453. //
  454. // HardwareId is a MULTI_SZ - we need a bug buffer.
  455. //
  456. HardwareId = (PWCHAR)malloc(ER_WD_MAX_DATA_SIZE);
  457. if (NULL == HardwareId)
  458. {
  459. return;
  460. }
  461. //
  462. // Get HardwareId string from registry.
  463. //
  464. Length = ER_WD_MAX_DATA_SIZE;
  465. WinStatus = RegQueryValueEx(Key,
  466. L"HardwareId",
  467. NULL,
  468. &Type,
  469. (LPBYTE)HardwareId,
  470. &Length);
  471. if (ERROR_SUCCESS != WinStatus)
  472. {
  473. free(HardwareId);
  474. return;
  475. }
  476. //
  477. // Make sure HardwareId is in uppercase.
  478. //
  479. _wcsupr(HardwareId);
  480. //
  481. // Get VendorId.
  482. //
  483. Token = wcsstr(HardwareId, L"VEN_");
  484. if (NULL != Token)
  485. {
  486. PciId->VendorId = (USHORT)wcstoul(Token + 4, &EndPointer, 16);
  487. }
  488. //
  489. // Get DeviceId.
  490. //
  491. Token = wcsstr(HardwareId, L"DEV_");
  492. if (NULL != Token)
  493. {
  494. PciId->DeviceId = (USHORT)wcstoul(Token + 4, &EndPointer, 16);
  495. }
  496. //
  497. // Get Revision.
  498. //
  499. Token = wcsstr(HardwareId, L"REV_");
  500. if (NULL != Token)
  501. {
  502. PciId->Revision = (UCHAR)wcstoul(Token + 4, &EndPointer, 16);
  503. }
  504. //
  505. // Get SubsystemId.
  506. //
  507. Token = wcsstr(HardwareId, L"SUBSYS_");
  508. if (NULL != Token)
  509. {
  510. PciId->SubsystemId = wcstoul(Token + 7, &EndPointer, 16);
  511. }
  512. free(HardwareId);
  513. }
  514. BOOL
  515. SaveWatchdogEventData(
  516. IN HANDLE FileHandle,
  517. IN HKEY Key,
  518. IN PER_WD_DRIVER_INFO DriverInfo
  519. )
  520. /*++
  521. Routine Description:
  522. This routine transfers watchdog event data from registry to
  523. the watchdog event report file.
  524. Arguments:
  525. FileHandle - Handle of open watchdog event report file.
  526. Key - Watchdog open key (device specific).
  527. Return Value:
  528. TRUE if successful, FALSE otherwise.
  529. --*/
  530. {
  531. LONG WinStatus;
  532. DWORD Index;
  533. DWORD NameLength;
  534. DWORD DataSize;
  535. DWORD ReturnedSize;
  536. DWORD Type;
  537. WCHAR Name[ER_WD_MAX_NAME_LENGTH + 1];
  538. WCHAR DwordBuffer[20];
  539. PBYTE Data;
  540. BOOL Status = TRUE;
  541. ASSERT(INVALID_HANDLE_VALUE != FileHandle);
  542. Data = (PBYTE)malloc(ER_WD_MAX_DATA_SIZE);
  543. if (NULL == Data)
  544. {
  545. return FALSE;
  546. }
  547. //
  548. // Pull watchdog data from registry and write it to report.
  549. //
  550. for (Index = 0;; Index++)
  551. {
  552. //
  553. // Read watchdog registry value.
  554. //
  555. NameLength = ER_WD_MAX_NAME_LENGTH;
  556. DataSize = ER_WD_MAX_DATA_SIZE;
  557. WinStatus = RegEnumValue(Key,
  558. Index,
  559. Name,
  560. &NameLength,
  561. NULL,
  562. &Type,
  563. Data,
  564. &DataSize);
  565. if (ERROR_NO_MORE_ITEMS == WinStatus)
  566. {
  567. break;
  568. }
  569. if (ERROR_SUCCESS != WinStatus)
  570. {
  571. continue;
  572. }
  573. //
  574. // Pick up strings and dwords only.
  575. //
  576. if ((REG_EXPAND_SZ == Type) || (REG_SZ == Type) || (REG_MULTI_SZ == Type) || (REG_DWORD == Type))
  577. {
  578. //
  579. // Write registry entry to watchdog event file.
  580. //
  581. Status = WriteWatchdogEventFile(FileHandle, Name);
  582. if (TRUE != Status)
  583. {
  584. break;
  585. }
  586. Status = WriteWatchdogEventFile(FileHandle, L": ");
  587. if (TRUE != Status)
  588. {
  589. break;
  590. }
  591. if (REG_DWORD == Type)
  592. {
  593. swprintf(DwordBuffer, L"%u", *(PULONG)Data);
  594. Status = WriteWatchdogEventFile(FileHandle, DwordBuffer);
  595. }
  596. else
  597. {
  598. Status = WriteWatchdogEventFile(FileHandle, (PWSTR)Data);
  599. }
  600. if (TRUE != Status)
  601. {
  602. break;
  603. }
  604. Status = WriteWatchdogEventFile(FileHandle, L"\r\n");
  605. if (TRUE != Status)
  606. {
  607. break;
  608. }
  609. }
  610. }
  611. //
  612. // Write driver info to report.
  613. //
  614. if (NULL != DriverInfo)
  615. {
  616. if (TRUE == Status)
  617. {
  618. swprintf((PWCHAR)Data, L"DriverFixedFileInfo: %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X\r\n",
  619. DriverInfo->FixedFileInfo.dwSignature,
  620. DriverInfo->FixedFileInfo.dwStrucVersion,
  621. DriverInfo->FixedFileInfo.dwFileVersionMS,
  622. DriverInfo->FixedFileInfo.dwFileVersionLS,
  623. DriverInfo->FixedFileInfo.dwProductVersionMS,
  624. DriverInfo->FixedFileInfo.dwProductVersionLS,
  625. DriverInfo->FixedFileInfo.dwFileFlagsMask,
  626. DriverInfo->FixedFileInfo.dwFileFlags,
  627. DriverInfo->FixedFileInfo.dwFileOS,
  628. DriverInfo->FixedFileInfo.dwFileType,
  629. DriverInfo->FixedFileInfo.dwFileSubtype,
  630. DriverInfo->FixedFileInfo.dwFileDateMS,
  631. DriverInfo->FixedFileInfo.dwFileDateLS);
  632. Status = WriteWatchdogEventFile(FileHandle, (PWCHAR)Data);
  633. }
  634. if ((TRUE == Status) && DriverInfo->Comments[0])
  635. {
  636. swprintf((PWCHAR)Data, L"DriverComments: %s\r\n", DriverInfo->Comments);
  637. Status = WriteWatchdogEventFile(FileHandle, (PWCHAR)Data);
  638. }
  639. if ((TRUE == Status) && DriverInfo->CompanyName[0])
  640. {
  641. swprintf((PWCHAR)Data, L"DriverCompanyName: %s\r\n", DriverInfo->CompanyName);
  642. Status = WriteWatchdogEventFile(FileHandle, (PWCHAR)Data);
  643. }
  644. if ((TRUE == Status) && DriverInfo->FileDescription[0])
  645. {
  646. swprintf((PWCHAR)Data, L"DriverFileDescription: %s\r\n", DriverInfo->FileDescription);
  647. Status = WriteWatchdogEventFile(FileHandle, (PWCHAR)Data);
  648. }
  649. if ((TRUE == Status) && DriverInfo->FileVersion[0])
  650. {
  651. swprintf((PWCHAR)Data, L"DriverFileVersion: %s\r\n", DriverInfo->FileVersion);
  652. Status = WriteWatchdogEventFile(FileHandle, (PWCHAR)Data);
  653. }
  654. if ((TRUE == Status) && DriverInfo->InternalName[0])
  655. {
  656. swprintf((PWCHAR)Data, L"DriverInternalName: %s\r\n", DriverInfo->InternalName);
  657. Status = WriteWatchdogEventFile(FileHandle, (PWCHAR)Data);
  658. }
  659. if ((TRUE == Status) && DriverInfo->LegalCopyright[0])
  660. {
  661. swprintf((PWCHAR)Data, L"DriverLegalCopyright: %s\r\n", DriverInfo->LegalCopyright);
  662. Status = WriteWatchdogEventFile(FileHandle, (PWCHAR)Data);
  663. }
  664. if ((TRUE == Status) && DriverInfo->LegalTrademarks[0])
  665. {
  666. swprintf((PWCHAR)Data, L"DriverLegalTrademarks: %s\r\n", DriverInfo->LegalTrademarks);
  667. Status = WriteWatchdogEventFile(FileHandle, (PWCHAR)Data);
  668. }
  669. if ((TRUE == Status) && DriverInfo->OriginalFilename[0])
  670. {
  671. swprintf((PWCHAR)Data, L"DriverOriginalFilename: %s\r\n", DriverInfo->OriginalFilename);
  672. Status = WriteWatchdogEventFile(FileHandle, (PWCHAR)Data);
  673. }
  674. if ((TRUE == Status) && DriverInfo->PrivateBuild[0])
  675. {
  676. swprintf((PWCHAR)Data, L"DriverPrivateBuild: %s\r\n", DriverInfo->PrivateBuild);
  677. Status = WriteWatchdogEventFile(FileHandle, (PWCHAR)Data);
  678. }
  679. if ((TRUE == Status) && DriverInfo->ProductName[0])
  680. {
  681. swprintf((PWCHAR)Data, L"DriverProductName: %s\r\n", DriverInfo->ProductName);
  682. Status = WriteWatchdogEventFile(FileHandle, (PWCHAR)Data);
  683. }
  684. if ((TRUE == Status) && DriverInfo->ProductVersion[0])
  685. {
  686. swprintf((PWCHAR)Data, L"DriverProductVersion: %s\r\n", DriverInfo->ProductVersion);
  687. Status = WriteWatchdogEventFile(FileHandle, (PWCHAR)Data);
  688. }
  689. if ((TRUE == Status) && DriverInfo->SpecialBuild[0])
  690. {
  691. swprintf((PWCHAR)Data, L"DriverSpecialBuild: %s\r\n", DriverInfo->SpecialBuild);
  692. Status = WriteWatchdogEventFile(FileHandle, (PWCHAR)Data);
  693. }
  694. }
  695. if (NULL != Data)
  696. {
  697. free(Data);
  698. Data = NULL;
  699. }
  700. return Status;
  701. }
  702. BOOL
  703. WatchdogEventHandler(
  704. IN BOOL NotifyPcHealth
  705. )
  706. /*++
  707. Routine Description:
  708. This is the boot time routine to handle pending watchdog events.
  709. Arguments:
  710. NotifyPcHealth - TRUE if we should report event to PC Health, FALSE otherwise.
  711. Return Value:
  712. TRUE if watchdog event(s) found and reported to PC Health, FALSE otherwise.
  713. --*/
  714. {
  715. HKEY Key;
  716. UCHAR Flags;
  717. ULONG WinStatus;
  718. ULONG Type;
  719. ULONG Length;
  720. ULONG Shutdown;
  721. ULONG EventFlag;
  722. ULONG Index;
  723. ULONG FileVersionMS;
  724. ULONG FileVersionLS;
  725. USHORT Signature;
  726. SEventInfoW EventInfo;
  727. HANDLE FileHandle;
  728. WCHAR WatchdogReport[MAX_PATH];
  729. WCHAR Stage1Url[ER_WD_MAX_URL_LENGTH + 1];
  730. WCHAR Stage2Url[ER_WD_MAX_URL_LENGTH + 1];
  731. WCHAR CorpPath[MAX_PATH];
  732. PWCHAR MessageBuffer;
  733. PWCHAR DescriptionBuffer;
  734. PWCHAR DeviceDescription;
  735. PWCHAR FinalReport;
  736. PWCHAR DriverName;
  737. PWCHAR String000;
  738. PWCHAR String001;
  739. PWCHAR String002;
  740. PWCHAR String003;
  741. PWCHAR String004;
  742. PWCHAR String005;
  743. BOOL LogStatus;
  744. BOOL ReturnStatus;
  745. HINSTANCE Instance;
  746. PER_WD_DRIVER_INFO DriverInfo;
  747. ER_WD_PCI_ID PciId;
  748. MessageBuffer = NULL;
  749. DescriptionBuffer = NULL;
  750. DeviceDescription = NULL;
  751. FinalReport = NULL;
  752. String000 = NULL;
  753. String001 = NULL;
  754. String002 = NULL;
  755. String003 = NULL;
  756. String004 = NULL;
  757. String005 = NULL;
  758. ReturnStatus = FALSE;
  759. Instance = (HINSTANCE)GetModuleHandle(NULL);
  760. DriverInfo = NULL;
  761. DriverName = NULL;
  762. //
  763. // Check if Watchdog\Display key present.
  764. // Note: Key not present = dirty shutdown but no watchdog event = we don't care.
  765. //
  766. WinStatus = RegOpenKey(HKEY_LOCAL_MACHINE,
  767. SUBKEY_WATCHDOG_DISPLAY,
  768. &Key);
  769. if (ERROR_SUCCESS == WinStatus)
  770. {
  771. EventFlag = 0;
  772. //
  773. // Check for clean shutdown indicator.
  774. //
  775. // TODO: Use NtQueryLastShutdownType() once implemented.
  776. //
  777. Length = sizeof (Shutdown);
  778. WinStatus = RegQueryValueEx(Key,
  779. L"Shutdown",
  780. NULL,
  781. &Type,
  782. (LPBYTE)&Shutdown,
  783. &Length);
  784. if (ERROR_SUCCESS != WinStatus)
  785. {
  786. //
  787. // Value not there - assume dirty shutdown.
  788. //
  789. Shutdown = 0;
  790. }
  791. //
  792. // If dirty shutdown check if watchdog display event captured.
  793. //
  794. if (!Shutdown)
  795. {
  796. Length = sizeof (EventFlag);
  797. WinStatus = RegQueryValueEx(Key,
  798. L"EventFlag",
  799. NULL,
  800. &Type,
  801. (LPBYTE)&EventFlag,
  802. &Length);
  803. if (ERROR_SUCCESS != WinStatus)
  804. {
  805. //
  806. // Value not there - watchdog display event not captured.
  807. //
  808. EventFlag = 0;
  809. }
  810. }
  811. if (EventFlag)
  812. {
  813. //
  814. // Report watchdog event to PC Health if requested.
  815. //
  816. if (NotifyPcHealth)
  817. {
  818. //
  819. // Allocate storage for localized strings.
  820. //
  821. String000 = (PWCHAR)malloc(ER_WD_MAX_STRING);
  822. String001 = (PWCHAR)malloc(ER_WD_MAX_STRING);
  823. String002 = (PWCHAR)malloc(ER_WD_MAX_STRING);
  824. String003 = (PWCHAR)malloc(ER_WD_MAX_STRING);
  825. String004 = (PWCHAR)malloc(ER_WD_MAX_STRING);
  826. String005 = (PWCHAR)malloc(ER_WD_MAX_STRING);
  827. //
  828. // Load localized strings from resources.
  829. //
  830. // Note: It's OK to pass NULL so we don't have to validate buffers.
  831. //
  832. LoadString(Instance, IDS_000, String000, ER_WD_MAX_STRING);
  833. LoadString(Instance, IDS_001, String001, ER_WD_MAX_STRING);
  834. LoadString(Instance, IDS_002, String002, ER_WD_MAX_STRING);
  835. LoadString(Instance, IDS_003, String003, ER_WD_MAX_STRING);
  836. LoadString(Instance, IDS_004, String004, ER_WD_MAX_STRING);
  837. LoadString(Instance, IDS_005, String005, ER_WD_MAX_STRING);
  838. //
  839. // Allocate and get DriverInfo data.
  840. //
  841. DriverInfo = (PER_WD_DRIVER_INFO)malloc(sizeof (ER_WD_DRIVER_INFO));
  842. if (NULL != DriverInfo)
  843. {
  844. GetDriverInfo(Key, L".dll", DriverInfo);
  845. }
  846. //
  847. // Get PCI ID info.
  848. //
  849. GetPciId(Key, &PciId);
  850. //
  851. // Get watchdog event flags.
  852. //
  853. Flags = GetFlags(Key);
  854. //
  855. // Generate event signature.
  856. //
  857. Signature = GenerateSignature(&PciId, DriverInfo);
  858. //
  859. // Create watchdog report file.
  860. //
  861. LogStatus = CreateWatchdogEventFileName(WatchdogReport);
  862. if (TRUE == LogStatus)
  863. {
  864. FileHandle = CreateWatchdogEventFile(WatchdogReport);
  865. if (INVALID_HANDLE_VALUE == FileHandle)
  866. {
  867. LogStatus = FALSE;
  868. }
  869. }
  870. else
  871. {
  872. FileHandle = INVALID_HANDLE_VALUE;
  873. }
  874. if (TRUE == LogStatus)
  875. {
  876. LogStatus = WriteWatchdogEventFile(
  877. FileHandle,
  878. L"\r\n//\r\n"
  879. L"// The driver for the display device got stuck in an infinite loop. This\r\n"
  880. L"// usually indicates a problem with the device itself or with the device\r\n"
  881. L"// driver programming the hardware incorrectly. Please check with your\r\n"
  882. L"// display device vendor for any driver updates.\r\n"
  883. L"//\r\n\r\n");
  884. }
  885. if (TRUE == LogStatus)
  886. {
  887. LogStatus = SaveWatchdogEventData(FileHandle, Key, DriverInfo);
  888. }
  889. if (INVALID_HANDLE_VALUE != FileHandle)
  890. {
  891. CloseHandle(FileHandle);
  892. }
  893. FinalReport = (TRUE == LogStatus) ? WatchdogReport : NULL;
  894. //
  895. // Get device description.
  896. //
  897. DescriptionBuffer = NULL;
  898. DeviceDescription = NULL;
  899. Length = 0;
  900. WinStatus = RegQueryValueEx(Key,
  901. L"DeviceDescription",
  902. NULL,
  903. &Type,
  904. NULL,
  905. &Length);
  906. if (ERROR_SUCCESS == WinStatus)
  907. {
  908. DescriptionBuffer = (PWCHAR)malloc(Length);
  909. if (NULL != DescriptionBuffer)
  910. {
  911. WinStatus = RegQueryValueEx(Key,
  912. L"DeviceDescription",
  913. NULL,
  914. &Type,
  915. (LPBYTE)DescriptionBuffer,
  916. &Length);
  917. }
  918. else
  919. {
  920. Length = 0;
  921. }
  922. }
  923. if ((ERROR_SUCCESS == WinStatus) && (0 != Length))
  924. {
  925. DeviceDescription = DescriptionBuffer;
  926. }
  927. else
  928. {
  929. DeviceDescription = String004;
  930. Length = (ER_WD_MAX_STRING + 1) * sizeof (WCHAR);
  931. }
  932. Length += 2 * ER_WD_MAX_STRING * sizeof (WCHAR);
  933. MessageBuffer = (PWCHAR)malloc(Length);
  934. if (NULL != MessageBuffer)
  935. {
  936. swprintf(MessageBuffer,
  937. L"%s%s%s",
  938. String003,
  939. DeviceDescription,
  940. String005);
  941. }
  942. //
  943. // Create URLs and corporate path.
  944. //
  945. if (DriverInfo)
  946. {
  947. DriverName = DriverInfo->DriverName;
  948. FileVersionMS = DriverInfo->FixedFileInfo.dwFileVersionMS;
  949. FileVersionLS = DriverInfo->FixedFileInfo.dwFileVersionLS;
  950. }
  951. else
  952. {
  953. DriverName = L"Unknown";
  954. FileVersionMS = 0;
  955. FileVersionLS = 0;
  956. }
  957. swprintf(Stage1Url,
  958. L"\r\nStage1URL=/StageOne/Drivers_Display/%04X%04X%02X%08X/%s/%u_%u_%u_%u/%04X%02X%02X",
  959. PciId.VendorId,
  960. PciId.DeviceId,
  961. PciId.Revision,
  962. PciId.SubsystemId,
  963. DriverName,
  964. (USHORT)(FileVersionMS >> 16),
  965. (USHORT)(FileVersionMS & 0xffff),
  966. (USHORT)(FileVersionLS >> 16),
  967. (USHORT)(FileVersionLS & 0xffff),
  968. Signature,
  969. Flags,
  970. 0xea);
  971. swprintf(Stage2Url,
  972. L"\r\nStage2URL=/dw/StageTwo.asp?szAppName=Drivers.Display&szAppVer=%04X%04X%02X%08X&"
  973. L"szModName=%s&szModVer=%u.%u.%u.%u&Offset=%04X%02X%02X",
  974. PciId.VendorId,
  975. PciId.DeviceId,
  976. PciId.Revision,
  977. PciId.SubsystemId,
  978. DriverName,
  979. (USHORT)(FileVersionMS >> 16),
  980. (USHORT)(FileVersionMS & 0xffff),
  981. (USHORT)(FileVersionLS >> 16),
  982. (USHORT)(FileVersionLS & 0xffff),
  983. Signature,
  984. Flags,
  985. 0xea);
  986. swprintf(CorpPath,
  987. L"\\Drivers.Display\\%04X%04X%02X%08X\\%s\\%u.%u.%u.%u\\%04X%02X%02X",
  988. PciId.VendorId,
  989. PciId.DeviceId,
  990. PciId.Revision,
  991. PciId.SubsystemId,
  992. DriverName,
  993. (USHORT)(FileVersionMS >> 16),
  994. (USHORT)(FileVersionMS & 0xffff),
  995. (USHORT)(FileVersionLS >> 16),
  996. (USHORT)(FileVersionLS & 0xffff),
  997. Signature,
  998. Flags,
  999. 0xea);
  1000. //
  1001. // Dots are not allowed in stage1 URL, replace with _ then append .htm.
  1002. //
  1003. for (Index = 0; Stage1Url[Index] != UNICODE_NULL; Index++)
  1004. {
  1005. if (Stage1Url[Index] == L'.')
  1006. {
  1007. Stage1Url[Index] = L'_';
  1008. }
  1009. }
  1010. wcscat(Stage1Url, L".htm");
  1011. //
  1012. // Fill in event record.
  1013. //
  1014. // TODO: Add minidump to watchdog event reports, but only when it contains stack trace
  1015. // from the spinning thread. This is for SKUs < Server, since we're not bugchecking
  1016. // for Server and above. We should also look into snapshot report, this can be good
  1017. // piece of data to send along.
  1018. //
  1019. ZeroMemory(&EventInfo, sizeof (EventInfo));
  1020. EventInfo.cbSEI = sizeof (EventInfo);
  1021. EventInfo.wszEventName = L"Thread Stuck in Device Driver";
  1022. EventInfo.wszErrMsg = String002;
  1023. EventInfo.wszHdr = String001;
  1024. EventInfo.wszTitle = String000;
  1025. EventInfo.wszStage1 = Stage1Url;
  1026. EventInfo.wszStage2 = Stage2Url;
  1027. EventInfo.wszFileList = FinalReport;
  1028. EventInfo.wszEventSrc = NULL;
  1029. EventInfo.wszCorpPath = CorpPath;
  1030. EventInfo.wszPlea = MessageBuffer;
  1031. EventInfo.wszSendBtn = NULL;
  1032. EventInfo.wszNoSendBtn = NULL;
  1033. EventInfo.fUseLitePlea = FALSE;
  1034. EventInfo.fUseIEForURLs = TRUE;
  1035. EventInfo.fNoBucketLogs = FALSE;
  1036. EventInfo.fNoDefCabLimit = FALSE;
  1037. //
  1038. // Notify PC Health.
  1039. //
  1040. PCHPFNotifyFault(eetUseEventInfo, NULL, &EventInfo);
  1041. //
  1042. // Clean up buffers.
  1043. //
  1044. if (NULL != DescriptionBuffer)
  1045. {
  1046. free(DescriptionBuffer);
  1047. DescriptionBuffer = NULL;
  1048. }
  1049. if (NULL != MessageBuffer)
  1050. {
  1051. free(MessageBuffer);
  1052. MessageBuffer = NULL;
  1053. }
  1054. if (NULL != String000)
  1055. {
  1056. free(String000);
  1057. String000 = NULL;
  1058. }
  1059. if (NULL != String001)
  1060. {
  1061. free(String001);
  1062. String001 = NULL;
  1063. }
  1064. if (NULL != String002)
  1065. {
  1066. free(String002);
  1067. String002 = NULL;
  1068. }
  1069. if (NULL != String003)
  1070. {
  1071. free(String003);
  1072. String003 = NULL;
  1073. }
  1074. if (NULL != String004)
  1075. {
  1076. free(String004);
  1077. String004 = NULL;
  1078. }
  1079. if (NULL != String005)
  1080. {
  1081. free(String005);
  1082. String005 = NULL;
  1083. }
  1084. if (NULL != DriverInfo)
  1085. {
  1086. free(DriverInfo);
  1087. DriverInfo = NULL;
  1088. }
  1089. //
  1090. // We trapped watchdog event and notified PC Health, set ReturnStatus to reflect this.
  1091. //
  1092. ReturnStatus = TRUE;
  1093. }
  1094. }
  1095. //
  1096. // Knock down watchdog's EventFlag. We do this after registering our
  1097. // event with PC Health.
  1098. //
  1099. RegDeleteValue(Key, L"EventFlag");
  1100. RegCloseKey(Key);
  1101. }
  1102. //
  1103. // TODO: Handle additional device classes here when supported.
  1104. //
  1105. return ReturnStatus;
  1106. }
  1107. BOOL
  1108. WriteWatchdogEventFile(
  1109. IN HANDLE FileHandle,
  1110. IN PWSTR String
  1111. )
  1112. /*++
  1113. Routine Description:
  1114. This routine writes a string to watchdog event report file.
  1115. Arguments:
  1116. FileHandle - Handle of open watchdog event report file.
  1117. String - Points to the string to write.
  1118. Return Value:
  1119. TRUE if successful, FALSE otherwise.
  1120. --*/
  1121. {
  1122. DWORD Size;
  1123. DWORD ReturnedSize;
  1124. PCHAR MultiByte;
  1125. BOOL Status;
  1126. ASSERT(INVALID_HANDLE_VALUE != FileHandle);
  1127. ASSERT(NULL != String);
  1128. //
  1129. // Get buffer size for translated string.
  1130. //
  1131. Size = WideCharToMultiByte(CP_ACP,
  1132. 0,
  1133. String,
  1134. -1,
  1135. NULL,
  1136. 0,
  1137. NULL,
  1138. NULL);
  1139. if (Size <= 1)
  1140. {
  1141. return TRUE;
  1142. }
  1143. MultiByte = (PCHAR)malloc(Size);
  1144. if (NULL == MultiByte)
  1145. {
  1146. return FALSE;
  1147. }
  1148. Size = WideCharToMultiByte(CP_ACP,
  1149. 0,
  1150. String,
  1151. -1,
  1152. MultiByte,
  1153. Size,
  1154. NULL,
  1155. NULL);
  1156. if (Size > 0)
  1157. {
  1158. Status = WriteFile(FileHandle,
  1159. MultiByte,
  1160. Size - 1,
  1161. &ReturnedSize,
  1162. NULL);
  1163. }
  1164. else
  1165. {
  1166. ASSERT(FALSE);
  1167. Status = FALSE;
  1168. }
  1169. free(MultiByte);
  1170. return Status;
  1171. }