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.

345 lines
9.4 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. raisexcp.c
  5. Abstract:
  6. This module implements the internal kernel code to continue execution
  7. and raise a exception.
  8. Author:
  9. David N. Cutler (davec) 8-Aug-1990
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. --*/
  14. #include "ki.h"
  15. VOID
  16. KiContinuePreviousModeUser(
  17. IN PCONTEXT ContextRecord,
  18. IN PKEXCEPTION_FRAME ExceptionFrame,
  19. IN PKTRAP_FRAME TrapFrame,
  20. IN KPROCESSOR_MODE PreviousMode
  21. )
  22. /*++
  23. Routine Description:
  24. This function is called from KiContinue if PreviousMode is
  25. not KernelMode. In this case a kernel mode copy of the
  26. ContextRecord is made before calling KeContextToKframes.
  27. This is done in a seperate routine to save stack space for
  28. the common case which is PreviousMode == Kernel.
  29. N.B. This routine is called from within a try/except block
  30. that will be used to handle errors like invalid context.
  31. Arguments:
  32. ContextRecord - Supplies a pointer to a context record.
  33. ExceptionFrame - Supplies a pointer to an exception frame.
  34. TrapFrame - Supplies a pointer to a trap frame.
  35. PreviousMode - Not KernelMode.
  36. Return Value:
  37. None.
  38. --*/
  39. {
  40. CONTEXT ContextRecord2;
  41. //
  42. // Copy the context record to kernel mode space.
  43. //
  44. ProbeForReadSmallStructure(ContextRecord, sizeof(CONTEXT), CONTEXT_ALIGN);
  45. RtlCopyMemory(&ContextRecord2, ContextRecord, sizeof(CONTEXT));
  46. ContextRecord = &ContextRecord2;
  47. //
  48. // Move information from the context record to the exception
  49. // and trap frames.
  50. //
  51. KeContextToKframes(TrapFrame,
  52. ExceptionFrame,
  53. &ContextRecord2,
  54. ContextRecord2.ContextFlags,
  55. PreviousMode);
  56. }
  57. NTSTATUS
  58. KiContinue (
  59. IN PCONTEXT ContextRecord,
  60. IN PKEXCEPTION_FRAME ExceptionFrame,
  61. IN PKTRAP_FRAME TrapFrame
  62. )
  63. /*++
  64. Routine Description:
  65. This function is called to copy the specified context frame to the
  66. specified exception and trap frames for the continue system service.
  67. Arguments:
  68. ContextRecord - Supplies a pointer to a context record.
  69. ExceptionFrame - Supplies a pointer to an exception frame.
  70. TrapFrame - Supplies a pointer to a trap frame.
  71. Return Value:
  72. STATUS_ACCESS_VIOLATION is returned if the context record is not readable
  73. from user mode.
  74. STATUS_DATATYPE_MISALIGNMENT is returned if the context record is not
  75. properly aligned.
  76. STATUS_SUCCESS is returned if the context frame is copied successfully
  77. to the specified exception and trap frames.
  78. --*/
  79. {
  80. KPROCESSOR_MODE PreviousMode;
  81. NTSTATUS Status;
  82. KIRQL OldIrql;
  83. BOOLEAN IrqlChanged = FALSE;
  84. //
  85. // Synchronize with other context operations.
  86. //
  87. Status = STATUS_SUCCESS;
  88. if (KeGetCurrentIrql() < APC_LEVEL) {
  89. //
  90. // To support try-except and ExRaiseStatus in device driver code we
  91. // need to check if we are already at raised level.
  92. //
  93. IrqlChanged = TRUE;
  94. KeRaiseIrql(APC_LEVEL, &OldIrql);
  95. }
  96. //
  97. // Establish an exception handler and probe and capture the specified
  98. // context record if the previous mode is user. If the probe or copy
  99. // fails, then return the exception code as the function value. Else
  100. // copy the context record to the specified exception and trap frames,
  101. // and return success as the function value.
  102. //
  103. try {
  104. //
  105. // Get the previous processor mode. If the previous processor mode is
  106. // user, then probe and copy the specified context record.
  107. //
  108. PreviousMode = KeGetPreviousMode();
  109. if (PreviousMode != KernelMode) {
  110. KiContinuePreviousModeUser(ContextRecord,
  111. ExceptionFrame,
  112. TrapFrame,
  113. PreviousMode);
  114. } else {
  115. //
  116. // Move information from the context record to the exception
  117. // and trap frames.
  118. //
  119. KeContextToKframes(TrapFrame,
  120. ExceptionFrame,
  121. ContextRecord,
  122. ContextRecord->ContextFlags,
  123. PreviousMode);
  124. }
  125. //
  126. // If an exception occurs during the probe or copy of the context
  127. // record, then always handle the exception and return the exception
  128. // code as the status value.
  129. //
  130. } except(EXCEPTION_EXECUTE_HANDLER) {
  131. Status = GetExceptionCode();
  132. }
  133. if (IrqlChanged) {
  134. KeLowerIrql (OldIrql);
  135. }
  136. return Status;
  137. }
  138. NTSTATUS
  139. KiRaiseException (
  140. IN PEXCEPTION_RECORD ExceptionRecord,
  141. IN PCONTEXT ContextRecord,
  142. IN PKEXCEPTION_FRAME ExceptionFrame,
  143. IN PKTRAP_FRAME TrapFrame,
  144. IN BOOLEAN FirstChance
  145. )
  146. /*++
  147. Routine Description:
  148. This function is called to raise an exception. The exception can be
  149. raised as a first or second chance exception.
  150. Arguments:
  151. ExceptionRecord - Supplies a pointer to an exception record.
  152. ContextRecord - Supplies a pointer to a context record.
  153. ExceptionFrame - Supplies a pointer to an exception frame.
  154. TrapFrame - Supplies a pointer to a trap frame.
  155. FirstChance - Supplies a boolean value that specifies whether this is
  156. the first (TRUE) or second (FALSE) chance for the exception.
  157. Return Value:
  158. STATUS_ACCESS_VIOLATION is returned if either the exception or the context
  159. record is not readable from user mode.
  160. STATUS_DATATYPE_MISALIGNMENT is returned if the exception record or the
  161. context record are not properly aligned.
  162. STATUS_INVALID_PARAMETER is returned if the number of exception parameters
  163. is greater than the maximum allowable number of exception parameters.
  164. STATUS_SUCCESS is returned if the exception is dispatched and handled.
  165. --*/
  166. {
  167. CONTEXT ContextRecord2;
  168. EXCEPTION_RECORD ExceptionRecord2;
  169. ULONG Length;
  170. ULONG Params;
  171. KPROCESSOR_MODE PreviousMode;
  172. //
  173. // Establish an exception handler and probe the specified exception and
  174. // context records for read accessibility. If the probe fails, then
  175. // return the exception code as the service status. Else call the exception
  176. // dispatcher to dispatch the exception.
  177. //
  178. try {
  179. //
  180. // Get the previous processor mode. If the previous processor mode
  181. // is user, then probe and copy the specified exception and context
  182. // records.
  183. //
  184. PreviousMode = KeGetPreviousMode();
  185. if (PreviousMode != KernelMode) {
  186. ProbeForReadSmallStructure(ContextRecord, sizeof(CONTEXT), CONTEXT_ALIGN);
  187. ProbeForReadSmallStructure(ExceptionRecord,
  188. FIELD_OFFSET (EXCEPTION_RECORD, NumberParameters) +
  189. sizeof (ExceptionRecord->NumberParameters), sizeof(ULONG));
  190. Params = ExceptionRecord->NumberParameters;
  191. if (Params > EXCEPTION_MAXIMUM_PARAMETERS) {
  192. return STATUS_INVALID_PARAMETER;
  193. }
  194. //
  195. // The exception record structure is defined unlike others with trailing
  196. // information as being its maximum size rather than just a single trailing
  197. // element.
  198. //
  199. Length = (sizeof(EXCEPTION_RECORD) -
  200. ((EXCEPTION_MAXIMUM_PARAMETERS - Params) *
  201. sizeof(ExceptionRecord->ExceptionInformation[0])));
  202. //
  203. // The structure is currently less that 64k so we don't really need this probe.
  204. //
  205. ProbeForRead(ExceptionRecord, Length, sizeof(ULONG));
  206. //
  207. // Copy the exception and context record to local storage so an
  208. // access violation cannot occur during exception dispatching.
  209. //
  210. RtlCopyMemory(&ContextRecord2, ContextRecord, sizeof(CONTEXT));
  211. RtlCopyMemory(&ExceptionRecord2, ExceptionRecord, Length);
  212. ContextRecord = &ContextRecord2;
  213. ExceptionRecord = &ExceptionRecord2;
  214. //
  215. // The number of parameters might have changed after we validated but before we
  216. // copied the structure. Fix this up as lower levels might not like this.
  217. //
  218. ExceptionRecord->NumberParameters = Params;
  219. }
  220. //
  221. // If an exception occurs during the probe of the exception or context
  222. // record, then always handle the exception and return the exception code
  223. // as the status value.
  224. //
  225. } except(EXCEPTION_EXECUTE_HANDLER) {
  226. return GetExceptionCode();
  227. }
  228. //
  229. // Move information from the context record to the exception and
  230. // trap frames.
  231. //
  232. KeContextToKframes(TrapFrame,
  233. ExceptionFrame,
  234. ContextRecord,
  235. ContextRecord->ContextFlags,
  236. PreviousMode);
  237. //
  238. // Make sure the reserved bit is clear in the exception code and
  239. // perform exception dispatching.
  240. //
  241. // N.B. The reserved bit is used to differentiate internally gerarated
  242. // codes from codes generated by application programs.
  243. //
  244. ExceptionRecord->ExceptionCode &= 0xefffffff;
  245. KiDispatchException(ExceptionRecord,
  246. ExceptionFrame,
  247. TrapFrame,
  248. PreviousMode,
  249. FirstChance);
  250. return STATUS_SUCCESS;
  251. }