pcexcept.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. /*++
  2. Copyright (c) 2017 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. pcexcept.c
  9. Abstract:
  10. This module implements common interrupt dispatch functionality between
  11. x86 and AMD64 processors.
  12. Author:
  13. Evan Green 11-Jun-2017
  14. Environment:
  15. Kernel
  16. --*/
  17. //
  18. // ------------------------------------------------------------------- Includes
  19. //
  20. #include <minoca/kernel/kernel.h>
  21. #include <minoca/kernel/kdebug.h>
  22. #if __SIZEOF_LONG__ == 8
  23. #include <minoca/kernel/x64.h>
  24. #else
  25. #include <minoca/kernel/x86.h>
  26. #endif
  27. //
  28. // ---------------------------------------------------------------- Definitions
  29. //
  30. //
  31. // ----------------------------------------------- Internal Function Prototypes
  32. //
  33. //
  34. // ------------------------------------------------------ Data Type Definitions
  35. //
  36. //
  37. // -------------------------------------------------------------------- Globals
  38. //
  39. //
  40. // ------------------------------------------------------------------ Functions
  41. //
  42. VOID
  43. KeDispatchInterrupt (
  44. PTRAP_FRAME TrapFrame
  45. )
  46. /*++
  47. Routine Description:
  48. This routine dispatches a device interrupt.
  49. Arguments:
  50. Vector - Supplies the vector this interrupt came in on.
  51. TrapFrame - Supplies a pointer to the machine state immediately before the
  52. interrupt.
  53. Return Value:
  54. None.
  55. --*/
  56. {
  57. CYCLE_ACCOUNT PreviousPeriod;
  58. ASSERT(ArAreInterruptsEnabled() == FALSE);
  59. PreviousPeriod = KeBeginCycleAccounting(CycleAccountInterrupt);
  60. //
  61. // The vector byte was sign extended, so cast back down to get rid of the
  62. // high bytes.
  63. //
  64. HlDispatchInterrupt((UCHAR)(TrapFrame->ErrorCode), TrapFrame);
  65. KeBeginCycleAccounting(PreviousPeriod);
  66. return;
  67. }
  68. VOID
  69. KeDispatchBreakPointTrap (
  70. PTRAP_FRAME TrapFrame
  71. )
  72. /*++
  73. Routine Description:
  74. This routine dispatches a breakpoint trap.
  75. Arguments:
  76. TrapFrame - Supplies a pointer to the machine state immediately before the
  77. trap.
  78. Return Value:
  79. None.
  80. --*/
  81. {
  82. CYCLE_ACCOUNT PreviousPeriod;
  83. PKTHREAD Thread;
  84. ASSERT(ArAreInterruptsEnabled() == FALSE);
  85. if (IS_TRAP_FRAME_FROM_PRIVILEGED_MODE(TrapFrame) == FALSE) {
  86. PreviousPeriod = KeBeginCycleAccounting(CycleAccountKernel);
  87. ArEnableInterrupts();
  88. Thread = KeGetCurrentThread();
  89. PsSignalThread(Thread, SIGNAL_TRAP, NULL, TRUE);
  90. PsCheckRuntimeTimers(Thread);
  91. PsDispatchPendingSignals(Thread, TrapFrame);
  92. ArDisableInterrupts();
  93. KeBeginCycleAccounting(PreviousPeriod);
  94. } else {
  95. KdDebugExceptionHandler(EXCEPTION_BREAK, NULL, TrapFrame);
  96. }
  97. return;
  98. }
  99. VOID
  100. KeDispatchDivideByZeroTrap (
  101. PTRAP_FRAME TrapFrame
  102. )
  103. /*++
  104. Routine Description:
  105. This routine dispatches a divide-by-zero trap.
  106. Arguments:
  107. TrapFrame - Supplies a pointer to the machine state immediately before the
  108. trap.
  109. Return Value:
  110. None.
  111. --*/
  112. {
  113. CYCLE_ACCOUNT PreviousPeriod;
  114. PKTHREAD Thread;
  115. if (IS_TRAP_FRAME_FROM_PRIVILEGED_MODE(TrapFrame) == FALSE) {
  116. PreviousPeriod = KeBeginCycleAccounting(CycleAccountKernel);
  117. ASSERT(ArAreInterruptsEnabled() != FALSE);
  118. Thread = KeGetCurrentThread();
  119. PsSignalThread(Thread, SIGNAL_MATH_ERROR, NULL, TRUE);
  120. PsCheckRuntimeTimers(Thread);
  121. PsDispatchPendingSignals(Thread, TrapFrame);
  122. KeBeginCycleAccounting(PreviousPeriod);
  123. } else {
  124. KdDebugExceptionHandler(EXCEPTION_DIVIDE_BY_ZERO, NULL, TrapFrame);
  125. KeCrashSystem(CRASH_DIVIDE_BY_ZERO,
  126. (UINTN)TrapFrame,
  127. (UINTN)ArGetInstructionPointer(TrapFrame),
  128. 0,
  129. 0);
  130. }
  131. ArDisableInterrupts();
  132. return;
  133. }
  134. VOID
  135. KeDispatchFpuAccessTrap (
  136. PTRAP_FRAME TrapFrame
  137. )
  138. /*++
  139. Routine Description:
  140. This routine dispatches a floating point access trap.
  141. Arguments:
  142. TrapFrame - Supplies a pointer to the machine state immediately before the
  143. trap.
  144. Return Value:
  145. None.
  146. --*/
  147. {
  148. RUNLEVEL OldRunLevel;
  149. CYCLE_ACCOUNT PreviousPeriod;
  150. PKTHREAD Thread;
  151. //
  152. // FPU access faults are "trap" type gates, so they shouldn't disable
  153. // interrupts.
  154. //
  155. ASSERT(ArAreInterruptsEnabled() != FALSE);
  156. PreviousPeriod = KeBeginCycleAccounting(CycleAccountKernel);
  157. Thread = KeGetCurrentThread();
  158. //
  159. // If the thread has never used the FPU before, allocate FPU context while
  160. // still at low level.
  161. //
  162. if (Thread->FpuContext == NULL) {
  163. ASSERT((Thread->FpuFlags & THREAD_FPU_FLAG_IN_USE) == 0);
  164. Thread->FpuContext =
  165. ArAllocateFpuContext(PS_FPU_CONTEXT_ALLOCATION_TAG);
  166. if (Thread->FpuContext == NULL) {
  167. PsSignalThread(Thread, SIGNAL_BUS_ERROR, NULL, TRUE);
  168. goto DispatchFpuAccessTrapEnd;
  169. }
  170. }
  171. OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
  172. //
  173. // Restore context if this is not the thread's first time using the FPU. If
  174. // the thread happens to already have its state on the CPU, then there's no
  175. // need to do the restore.
  176. //
  177. if ((Thread->FpuFlags & THREAD_FPU_FLAG_IN_USE) != 0) {
  178. if ((Thread->FpuFlags & THREAD_FPU_FLAG_OWNER) != 0) {
  179. ArEnableFpu();
  180. } else {
  181. ArRestoreFpuState(Thread->FpuContext);
  182. }
  183. //
  184. // If this is the first time using the FPU, enable it, initialize it, and
  185. // mark the thread as using it. An NMI could come in between the enable
  186. // and initialize, which would cause the initialize to fault.
  187. //
  188. } else {
  189. ArEnableFpu();
  190. ArInitializeFpu();
  191. Thread->FpuFlags |= THREAD_FPU_FLAG_IN_USE;
  192. }
  193. Thread->FpuFlags |= THREAD_FPU_FLAG_OWNER;
  194. KeLowerRunLevel(OldRunLevel);
  195. DispatchFpuAccessTrapEnd:
  196. KeBeginCycleAccounting(PreviousPeriod);
  197. return;
  198. }
  199. VOID
  200. KeDispatchProtectionFault (
  201. PTRAP_FRAME TrapFrame
  202. )
  203. /*++
  204. Routine Description:
  205. This routine dispatches a protection fault trap.
  206. Arguments:
  207. TrapFrame - Supplies a pointer to the machine state immediately before the
  208. trap.
  209. Return Value:
  210. None.
  211. --*/
  212. {
  213. CYCLE_ACCOUNT PreviousPeriod;
  214. PKTHREAD Thread;
  215. if (IS_TRAP_FRAME_FROM_PRIVILEGED_MODE(TrapFrame) == FALSE) {
  216. PreviousPeriod = KeBeginCycleAccounting(CycleAccountKernel);
  217. ArEnableInterrupts();
  218. Thread = KeGetCurrentThread();
  219. PsHandleUserModeFault(NULL,
  220. FAULT_FLAG_PROTECTION_FAULT,
  221. TrapFrame,
  222. Thread->OwningProcess);
  223. PsCheckRuntimeTimers(Thread);
  224. PsDispatchPendingSignals(Thread, TrapFrame);
  225. KeBeginCycleAccounting(PreviousPeriod);
  226. } else {
  227. KdDebugExceptionHandler(EXCEPTION_ACCESS_VIOLATION, NULL, TrapFrame);
  228. KeCrashSystem(CRASH_PAGE_FAULT,
  229. (UINTN)TrapFrame,
  230. (UINTN)ArGetInstructionPointer(TrapFrame),
  231. 0,
  232. 0);
  233. }
  234. ArDisableInterrupts();
  235. return;
  236. }
  237. VOID
  238. KeDispatchMathFault (
  239. PTRAP_FRAME TrapFrame
  240. )
  241. /*++
  242. Routine Description:
  243. This routine dispatches a math fault from the x87 unit.
  244. Arguments:
  245. TrapFrame - Supplies a pointer to the machine state immediately before the
  246. trap.
  247. Return Value:
  248. None.
  249. --*/
  250. {
  251. CYCLE_ACCOUNT PreviousPeriod;
  252. PKTHREAD Thread;
  253. ASSERT(ArAreInterruptsEnabled() == FALSE);
  254. if (IS_TRAP_FRAME_FROM_PRIVILEGED_MODE(TrapFrame) == FALSE) {
  255. PreviousPeriod = KeBeginCycleAccounting(CycleAccountKernel);
  256. ArEnableInterrupts();
  257. Thread = KeGetCurrentThread();
  258. PsSignalThread(Thread, SIGNAL_MATH_ERROR, NULL, TRUE);
  259. PsCheckRuntimeTimers(Thread);
  260. PsDispatchPendingSignals(Thread, TrapFrame);
  261. KeBeginCycleAccounting(PreviousPeriod);
  262. } else {
  263. KdDebugExceptionHandler(EXCEPTION_MATH_FAULT, NULL, TrapFrame);
  264. KeCrashSystem(CRASH_MATH_FAULT,
  265. (UINTN)TrapFrame,
  266. (UINTN)ArGetInstructionPointer(TrapFrame),
  267. 0,
  268. 0);
  269. }
  270. ArDisableInterrupts();
  271. return;
  272. }
  273. VOID
  274. KeDispatchPageFault (
  275. PVOID FaultingAddress,
  276. PTRAP_FRAME TrapFrame
  277. )
  278. /*++
  279. Routine Description:
  280. This routine handles page faults.
  281. Arguments:
  282. FaultingAddress - Supplies the address that caused the fault.
  283. TrapFrame - Supplies a pointer to the trap frame of the fault.
  284. Return Value:
  285. None.
  286. --*/
  287. {
  288. ULONG FaultFlags;
  289. CYCLE_ACCOUNT PreviousPeriod;
  290. PreviousPeriod = KeBeginCycleAccounting(CycleAccountKernel);
  291. FaultFlags = 0;
  292. if ((TrapFrame->ErrorCode & X86_FAULT_ERROR_CODE_PRESENT) == 0) {
  293. FaultFlags |= FAULT_FLAG_PAGE_NOT_PRESENT;
  294. } else {
  295. FaultFlags |= FAULT_FLAG_PERMISSION_ERROR;
  296. }
  297. if ((TrapFrame->ErrorCode & X86_FAULT_ERROR_CODE_WRITE) != 0) {
  298. FaultFlags |= FAULT_FLAG_WRITE;
  299. }
  300. MmHandleFault(FaultFlags, FaultingAddress, TrapFrame);
  301. KeBeginCycleAccounting(PreviousPeriod);
  302. return;
  303. }
  304. //
  305. // --------------------------------------------------------- Internal Functions
  306. //