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.

206 lines
5.5 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. ixnmi.c
  5. Abstract:
  6. Provides standard x86 NMI handler
  7. Author:
  8. kenr
  9. Revision History:
  10. --*/
  11. #include "halp.h"
  12. #include "bugcodes.h"
  13. #include "inbv.h"
  14. #define SYSTEM_CONTROL_PORT_A 0x92
  15. #define SYSTEM_CONTROL_PORT_B 0x61
  16. #define EISA_EXTENDED_NMI_STATUS 0x461
  17. const UCHAR EisaNMIMsg[] = MSG_NMI_EISA_IOCHKERR;
  18. // The IRET performed in HalpBiosCall() called from HalpBiosDisplayReset()
  19. // under HalpDisplayString() allows a second NMI to occur.
  20. // This ends up causing a trap 0d because the NMI TSS is busy. Because
  21. // the normal trap 0d handler attempts to bugcheck which trashes the screen,
  22. // this flag (HalpNMIInProgress) tells HalpBiosDisplayReset() to leave its
  23. // trap 0d handler in place which will then just spin on a jump to self if
  24. // a second NMI occurs.
  25. volatile ULONG HalpNMIInProgress;
  26. BOOLEAN HalpNMIDumpFlag;
  27. VOID
  28. HalHandleNMI(
  29. IN OUT PVOID NmiInfo
  30. )
  31. /*++
  32. Routine Description:
  33. Called DURING an NMI. The system will BugCheck when an NMI occurs.
  34. This function can return the proper bugcheck code, bugcheck itself,
  35. or return success which will cause the system to iret from the nmi.
  36. This function is called during an NMI - no system services are available.
  37. In addition, you don't want to touch any spinlock which is normally
  38. used since we may have been interrupted while owning it, etc, etc...
  39. Warnings:
  40. Do NOT:
  41. Make any system calls
  42. Attempt to acquire any spinlock used by any code outside the NMI handler
  43. Change the interrupt state. Do not execute any IRET inside this code
  44. Passing data to non-NMI code must be done using manual interlocked
  45. functions. (xchg instructions).
  46. Arguments:
  47. NmiInfo - Pointer to NMI information structure (TBD)
  48. - NULL means no NMI information structure was passed
  49. Return Value:
  50. BugCheck code
  51. --*/
  52. {
  53. UCHAR StatusByte;
  54. UCHAR EisaPort;
  55. UCHAR c;
  56. ULONG port, i;
  57. #ifndef NT_UP
  58. #if defined(_AMD64_)
  59. static ULONG NMILock;
  60. while (InterlockedCompareExchange(&NMILock,1,0) != 0) {
  61. };
  62. #else
  63. static volatile ULONG NMILock;
  64. _asm {
  65. LockNMILock:
  66. lock bts NMILock, 0
  67. jc LockNMILock
  68. }
  69. #endif
  70. if (HalpNMIInProgress == 0) {
  71. #endif
  72. HalpNMIInProgress++;
  73. StatusByte = READ_PORT_UCHAR((PUCHAR) SYSTEM_CONTROL_PORT_B);
  74. //
  75. // Enable InbvDisplayString calls to make it through to bootvid driver.
  76. //
  77. if (InbvIsBootDriverInstalled()) {
  78. InbvAcquireDisplayOwnership();
  79. InbvResetDisplay();
  80. InbvSolidColorFill(0,0,639,479,4); // make the screen blue
  81. InbvSetTextColor(15);
  82. InbvInstallDisplayStringFilter((INBV_DISPLAY_STRING_FILTER)NULL);
  83. InbvEnableDisplayString(TRUE); // enable display string
  84. InbvSetScrollRegion(0,0,639,479); // set to use entire screen
  85. }
  86. HalDisplayString (MSG_HARDWARE_ERROR1);
  87. HalDisplayString (MSG_HARDWARE_ERROR2);
  88. if (StatusByte & 0x80) {
  89. HalDisplayString (MSG_NMI_PARITY);
  90. }
  91. if (StatusByte & 0x40) {
  92. HalDisplayString (MSG_NMI_CHANNEL_CHECK);
  93. }
  94. if (HalpBusType == MACHINE_TYPE_EISA) {
  95. //
  96. // This is an Eisa machine, check for extnded nmi information...
  97. //
  98. StatusByte = READ_PORT_UCHAR((PUCHAR) EISA_EXTENDED_NMI_STATUS);
  99. if (StatusByte & 0x80) {
  100. HalDisplayString (MSG_NMI_FAIL_SAFE);
  101. }
  102. if (StatusByte & 0x40) {
  103. HalDisplayString (MSG_NMI_BUS_TIMEOUT);
  104. }
  105. if (StatusByte & 0x20) {
  106. HalDisplayString (MSG_NMI_SOFTWARE_NMI);
  107. }
  108. //
  109. // Look for any Eisa expansion board. See if it asserted NMI.
  110. //
  111. for (EisaPort = 1; EisaPort <= 0xf; EisaPort++) {
  112. port = (EisaPort << 12) + 0xC80;
  113. WRITE_PORT_UCHAR ((PUCHAR) (ULONG_PTR)port, 0xff);
  114. StatusByte = READ_PORT_UCHAR ((PUCHAR) (ULONG_PTR)port);
  115. if ((StatusByte & 0x80) == 0) {
  116. //
  117. // Found valid Eisa board, Check to see if it's
  118. // if IOCHKERR is asserted.
  119. //
  120. StatusByte = READ_PORT_UCHAR ((PUCHAR) (ULONG_PTR)port+4);
  121. if (StatusByte & 0x2 && StatusByte != 0xff) {
  122. UCHAR Msg[sizeof(EisaNMIMsg)];
  123. RtlCopyMemory(Msg, EisaNMIMsg, sizeof(Msg));
  124. c = (EisaPort > 9 ? 'A'-10 : '0') + EisaPort;
  125. for (i=0; Msg[i]; i++) {
  126. if (Msg[i] == '%') {
  127. Msg[i] = c;
  128. break;
  129. }
  130. }
  131. HalDisplayString (Msg);
  132. }
  133. }
  134. }
  135. }
  136. HalDisplayString (MSG_HALT);
  137. if (HalpNMIDumpFlag) {
  138. KeBugCheckEx(NMI_HARDWARE_FAILURE,(ULONG)'ODT',0,0,0);
  139. }
  140. #ifndef NT_UP
  141. }
  142. NMILock = 0;
  143. #endif
  144. if ((*((PBOOLEAN)(*(PLONG_PTR)&KdDebuggerNotPresent)) == FALSE) &&
  145. (**((PUCHAR *)&KdDebuggerEnabled) != FALSE)) {
  146. KeEnterKernelDebugger();
  147. }
  148. while(TRUE) {
  149. // Just sit here so that screen does not get corrupted.
  150. }
  151. }