xref: /reactos/ntoskrnl/ke/arm/exp.c (revision 54d5ad75)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * LICENSE:         BSD - See COPYING.ARM in the top level directory
4  * FILE:            ntoskrnl/ke/arm/exp.c
5  * PURPOSE:         Implements exception helper routines for ARM machines
6  * PROGRAMMERS:     ReactOS Portable Systems Group
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 /* FUNCTIONS ******************************************************************/
16 
17 VOID
18 NTAPI
KeContextToTrapFrame(IN PCONTEXT Context,IN OUT PKEXCEPTION_FRAME ExceptionFrame,IN OUT PKTRAP_FRAME TrapFrame,IN ULONG ContextFlags,IN KPROCESSOR_MODE PreviousMode)19 KeContextToTrapFrame(IN PCONTEXT Context,
20                      IN OUT PKEXCEPTION_FRAME ExceptionFrame,
21                      IN OUT PKTRAP_FRAME TrapFrame,
22                      IN ULONG ContextFlags,
23                      IN KPROCESSOR_MODE PreviousMode)
24 {
25     KIRQL OldIrql;
26 
27     //
28     // Do this at APC_LEVEL
29     //
30     OldIrql = KeGetCurrentIrql();
31     if (OldIrql < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
32 
33     //
34     // Start with the Control flags
35     //
36     if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
37     {
38         //
39         // So this basically means all the special stuff
40         //
41 
42         //
43         // ARM has register banks
44         //
45         TrapFrame->Sp = Context->Sp;
46         TrapFrame->Lr = Context->Lr;
47 
48         //
49         // The rest is already in the right mode
50         //
51         TrapFrame->Pc = Context->Pc;
52         TrapFrame->Cpsr = Context->Cpsr;
53     }
54 
55     //
56     // Now do the integers
57     //
58     if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
59     {
60         //
61         // Basically everything else but FPU
62         //
63         TrapFrame->R0 = Context->R0;
64         TrapFrame->R1 = Context->R1;
65         TrapFrame->R2 = Context->R2;
66         TrapFrame->R3 = Context->R3;
67         ExceptionFrame->R4 = Context->R4;
68         ExceptionFrame->R5 = Context->R5;
69         ExceptionFrame->R6 = Context->R6;
70         ExceptionFrame->R7 = Context->R7;
71         ExceptionFrame->R8 = Context->R8;
72         ExceptionFrame->R9 = Context->R9;
73         ExceptionFrame->R10 = Context->R10;
74         ExceptionFrame->R11 = Context->R11;
75         TrapFrame->R12 = Context->R12;
76     }
77 
78     //
79     // Restore IRQL
80     //
81     if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
82 }
83 
84 VOID
85 NTAPI
KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame,IN PKEXCEPTION_FRAME ExceptionFrame,IN OUT PCONTEXT Context)86 KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame,
87                      IN PKEXCEPTION_FRAME ExceptionFrame,
88                      IN OUT PCONTEXT Context)
89 {
90     KIRQL OldIrql;
91 
92     //
93     // Do this at APC_LEVEL
94     //
95     OldIrql = KeGetCurrentIrql();
96     if (OldIrql < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
97 
98     //
99     // Start with the Control flags
100     //
101     if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
102     {
103         //
104         // So this basically means all the special stuff
105         //
106 
107         //
108         // ARM has register banks
109         //
110         Context->Sp = TrapFrame->Sp;
111         Context->Lr = TrapFrame->Lr;
112 
113         //
114         // The rest is already in the right mode
115         //
116         Context->Pc = TrapFrame->Pc;
117         Context->Cpsr = TrapFrame->Cpsr;
118     }
119 
120     //
121     // Now do the integers
122     //
123     if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
124     {
125         //
126         // Basically everything else but FPU
127         //
128         Context->R0 = TrapFrame->R0;
129         Context->R1 = TrapFrame->R1;
130         Context->R2 = TrapFrame->R2;
131         Context->R3 = TrapFrame->R3;
132         Context->R4 = ExceptionFrame->R4;
133         Context->R5 = ExceptionFrame->R5;
134         Context->R6 = ExceptionFrame->R6;
135         Context->R7 = ExceptionFrame->R7;
136         Context->R8 = ExceptionFrame->R8;
137         Context->R9 = ExceptionFrame->R9;
138         Context->R10 = ExceptionFrame->R10;
139         Context->R11 = ExceptionFrame->R11;
140         Context->R12 = TrapFrame->R12;
141     }
142 
143     //
144     // Restore IRQL
145     //
146     if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
147 }
148 
149 VOID
150 NTAPI
KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,IN PKEXCEPTION_FRAME ExceptionFrame,IN PKTRAP_FRAME TrapFrame,IN KPROCESSOR_MODE PreviousMode,IN BOOLEAN FirstChance)151 KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
152                     IN PKEXCEPTION_FRAME ExceptionFrame,
153                     IN PKTRAP_FRAME TrapFrame,
154                     IN KPROCESSOR_MODE PreviousMode,
155                     IN BOOLEAN FirstChance)
156 {
157     CONTEXT Context;
158 
159     /* Increase number of Exception Dispatches */
160     KeGetCurrentPrcb()->KeExceptionDispatchCount++;
161 
162     /* Set the context flags */
163     Context.ContextFlags = CONTEXT_FULL;
164 
165     /* Check if User Mode or if the kernel debugger is enabled */
166     if ((PreviousMode == UserMode) || (KeGetPcr()->KdVersionBlock))
167     {
168         /* FIXME-V6: VFP Support */
169     }
170 
171     /* Get a Context */
172     KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);
173 
174     /* Look at our exception code */
175     switch (ExceptionRecord->ExceptionCode)
176     {
177         /* Breakpoint */
178         case STATUS_BREAKPOINT:
179 
180             /* Decrement PC by four */
181             Context.Pc -= sizeof(ULONG);
182             break;
183 
184         /* Internal exception */
185         case KI_EXCEPTION_ACCESS_VIOLATION:
186 
187             /* Set correct code */
188             ExceptionRecord->ExceptionCode = STATUS_ACCESS_VIOLATION;
189             if (PreviousMode == UserMode)
190             {
191                 /* FIXME: Handle no execute */
192             }
193             break;
194     }
195 
196     /* Handle kernel-mode first, it's simpler */
197     if (PreviousMode == KernelMode)
198     {
199         /* Check if this is a first-chance exception */
200         if (FirstChance != FALSE)
201         {
202             /* Break into the debugger for the first time */
203             if (KiDebugRoutine(TrapFrame,
204                                ExceptionFrame,
205                                ExceptionRecord,
206                                &Context,
207                                PreviousMode,
208                                FALSE))
209             {
210                 /* Exception was handled */
211                 goto Handled;
212             }
213 
214             /* If the Debugger couldn't handle it, dispatch the exception */
215             if (RtlDispatchException(ExceptionRecord, &Context)) goto Handled;
216         }
217 
218         /* This is a second-chance exception, only for the debugger */
219         if (KiDebugRoutine(TrapFrame,
220                            ExceptionFrame,
221                            ExceptionRecord,
222                            &Context,
223                            PreviousMode,
224                            TRUE))
225         {
226             /* Exception was handled */
227             goto Handled;
228         }
229 
230         /* Third strike; you're out */
231         KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED,
232                      ExceptionRecord->ExceptionCode,
233                      (ULONG_PTR)ExceptionRecord->ExceptionAddress,
234                      (ULONG_PTR)TrapFrame,
235                      0);
236     }
237     else
238     {
239         /* FIXME: TODO */
240         /* 3rd strike, kill the process */
241         DPRINT1("Kill %.16s, ExceptionCode: %lx, ExceptionAddress: %lx\n",
242                 PsGetCurrentProcess()->ImageFileName,
243                 ExceptionRecord->ExceptionCode,
244                 ExceptionRecord->ExceptionAddress);
245 
246         ZwTerminateProcess(NtCurrentProcess(), ExceptionRecord->ExceptionCode);
247         KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED,
248                      ExceptionRecord->ExceptionCode,
249                      (ULONG_PTR)ExceptionRecord->ExceptionAddress,
250                      (ULONG_PTR)TrapFrame,
251                      0);
252     }
253 
254 Handled:
255     /* Convert the context back into Trap/Exception Frames */
256     KeContextToTrapFrame(&Context,
257                          ExceptionFrame,
258                          TrapFrame,
259                          Context.ContextFlags,
260                          PreviousMode);
261     return;
262 }
263 
264 NTSTATUS
265 NTAPI
KeRaiseUserException(_In_ NTSTATUS ExceptionCode)266 KeRaiseUserException(
267     _In_ NTSTATUS ExceptionCode)
268 {
269     ASSERT(FALSE);
270     return STATUS_NOT_IMPLEMENTED;
271 }
272