ReactOS  0.4.15-dev-2704-gd5265b0
trapc.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Kernel
3  * LICENSE: BSD - See COPYING.ARM in the top level directory
4  * FILE: ntoskrnl/ke/arm/trapc.c
5  * PURPOSE: Implements the various trap handlers for ARM exceptions
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 #if 0
19 VOID
21 {
22  PKPCR Pcr = (PKPCR)KeGetPcr();
23  PKPRCB Prcb = Pcr->Prcb;
24  PKTHREAD OldThread, NewThread;
25 
26  //
27  // Loop forever... that's why this is an idle loop
28  //
29  DPRINT1("[IDLE LOOP]\n");
30  while (TRUE);
31 
32  while (TRUE)
33  {
34  //
35  // Cycle interrupts
36  //
37  _disable();
38  _enable();
39 
40  //
41  // Check if there's DPC work to do
42  //
43  if ((Prcb->DpcData[0].DpcQueueDepth) ||
44  (Prcb->TimerRequest) ||
46  {
47  //
48  // Clear the pending interrupt
49  //
51 
52  //
53  // Retire DPCs
54  //
55  KiRetireDpcList(Prcb);
56  }
57 
58  //
59  // Check if there's a thread to schedule
60  //
61  if (Prcb->NextThread)
62  {
63  //
64  // Out with the old, in with the new...
65  //
66  OldThread = Prcb->CurrentThread;
67  NewThread = Prcb->NextThread;
68  Prcb->CurrentThread = NewThread;
69  Prcb->NextThread = NULL;
70 
71  //
72  // Update thread state
73  //
74  NewThread->State = Running;
75 
76  //
77  // Swap to the new thread
78  // On ARM we call KiSwapContext instead of KiSwapContextInternal,
79  // because we're calling this from C code and not assembly.
80  // This is similar to how it gets called for unwaiting, on x86
81  //
82  KiSwapContext(OldThread, NewThread);
83  }
84  else
85  {
86  //
87  // Go into WFI (sleep more)
88  //
90  }
91  }
92 }
93 #endif
94 
95 VOID
96 NTAPI
98  IN PKPROCESS OldProcess)
99 {
100  ARM_TTB_REGISTER TtbRegister;
101  DPRINT1("Swapping from: %p (%16s) to %p (%16s)\n",
102  OldProcess, ((PEPROCESS)OldProcess)->ImageFileName,
103  NewProcess, ((PEPROCESS)NewProcess)->ImageFileName);
104 
105  //
106  // Update the page directory base
107  //
108  TtbRegister.AsUlong = NewProcess->DirectoryTableBase[0];
109  ASSERT(TtbRegister.Reserved == 0);
111 
112  //
113  // FIXME: Flush the TLB
114  //
115 
116 
117  DPRINT1("Survived!\n");
118  while (TRUE);
119 }
120 
121 #if 0
122 BOOLEAN
123 KiSwapContextInternal(IN PKTHREAD OldThread,
124  IN PKTHREAD NewThread)
125 {
126  PKIPCR Pcr = (PKIPCR)KeGetPcr();
127  PKPRCB Prcb = Pcr->Prcb;
128  PKPROCESS OldProcess, NewProcess;
129 
130  DPRINT1("SWAP\n");
131  while (TRUE);
132 
133  //
134  // Increase context switch count
135  //
136  Pcr->ContextSwitches++;
137 
138  //
139  // Check if WMI tracing is enabled
140  //
141  if (Pcr->PerfGlobalGroupMask)
142  {
143  //
144  // We don't support this yet on x86 either
145  //
146  DPRINT1("WMI Tracing not supported\n");
147  ASSERT(FALSE);
148  }
149 
150  //
151  // Check if the processes are also different
152  //
153  OldProcess = OldThread->ApcState.Process;
154  NewProcess = NewThread->ApcState.Process;
155  if (OldProcess != NewProcess)
156  {
157  //
158  // Check if address space switch is needed
159  //
160  if (OldProcess->DirectoryTableBase[0] !=
161  NewProcess->DirectoryTableBase[0])
162  {
163  //
164  // FIXME-USER: Support address space switch
165  //
166  DPRINT1("Address space switch not implemented\n");
167  ASSERT(FALSE);
168  }
169  }
170 
171  //
172  // Increase thread context switches
173  //
174  NewThread->ContextSwitches++;
175 #if 0 // I don't buy this
176  //
177  // Set us as the current thread
178  // NOTE: On RISC Platforms, there is both a KPCR CurrentThread, and a
179  // KPRCB CurrentThread.
180  // The latter is set just like on x86-based builds, the former is only set
181  // when actually doing the context switch (here).
182  // Recall that the reason for the latter is due to the fact that the KPCR
183  // is shared with user-mode (read-only), so that information is exposed
184  // there as well.
185  //
186  Pcr->CurrentThread = NewThread;
187 #endif
188  //
189  // DPCs shouldn't be active
190  //
191  if (Prcb->DpcRoutineActive)
192  {
193  //
194  // Crash the machine
195  //
196  KeBugCheckEx(ATTEMPTED_SWITCH_FROM_DPC,
197  (ULONG_PTR)OldThread,
198  (ULONG_PTR)NewThread,
199  (ULONG_PTR)OldThread->InitialStack,
200  0);
201  }
202 
203  //
204  // Kernel APCs may be pending
205  //
206  if (NewThread->ApcState.KernelApcPending)
207  {
208  //
209  // Are APCs enabled?
210  //
211  if (NewThread->SpecialApcDisable == 0)
212  {
213  //
214  // Request APC delivery
215  //
217  return TRUE;
218  }
219  }
220 
221  //
222  // Return
223  //
224  return FALSE;
225 }
226 #endif
227 
228 VOID
230 {
232  KEXCEPTION_FRAME ExceptionFrame;
233  PKTRAP_FRAME TrapFrame = KeGetCurrentThread()->TrapFrame;
234 
235  DPRINT1("[APC TRAP]\n");
236  while (TRUE);
237 
238  //
239  // Isolate previous mode
240  //
241  PreviousMode = KiGetPreviousMode(TrapFrame);
242 
243  //
244  // FIXME-USER: Handle APC interrupt while in user-mode
245  //
247 
248  //
249  // Disable interrupts
250  //
251  _disable();
252 
253  //
254  // Clear APC interrupt
255  //
257 
258  //
259  // Re-enable interrupts
260  //
261  _enable();
262 
263  //
264  // Deliver APCs
265  //
266  KiDeliverApc(PreviousMode, &ExceptionFrame, TrapFrame);
267 }
268 
269 #if 0
270 VOID
272 {
273  PKIPCR Pcr;
274  PKPRCB Prcb;
275  PKTHREAD NewThread, OldThread;
276 
277  DPRINT1("[DPC TRAP]\n");
278  while (TRUE);
279 
280  //
281  // Get the PCR and disable interrupts
282  //
283  Pcr = (PKIPCR)KeGetPcr();
284  Prcb = Pcr->Prcb;
285  _disable();
286 
287  //
288  //Check if we have to deliver DPCs, timers, or deferred threads
289  //
290  if ((Prcb->DpcData[0].DpcQueueDepth) ||
291  (Prcb->TimerRequest) ||
292  (Prcb->DeferredReadyListHead.Next))
293  {
294  //
295  // Retire DPCs
296  //
297  KiRetireDpcList(Prcb);
298  }
299 
300  //
301  // Re-enable interrupts
302  //
303  _enable();
304 
305  //
306  // Check for quantum end
307  //
308  if (Prcb->QuantumEnd)
309  {
310  //
311  // Handle quantum end
312  //
313  Prcb->QuantumEnd = FALSE;
314  KiQuantumEnd();
315  return;
316  }
317 
318  //
319  // Check if we have a thread to swap to
320  //
321  if (Prcb->NextThread)
322  {
323  //
324  // Next is now current
325  //
326  OldThread = Prcb->CurrentThread;
327  NewThread = Prcb->NextThread;
328  Prcb->CurrentThread = NewThread;
329  Prcb->NextThread = NULL;
330 
331  //
332  // Update thread states
333  //
334  NewThread->State = Running;
335  OldThread->WaitReason = WrDispatchInt;
336 
337  //
338  // Make the old thread ready
339  //
340  KxQueueReadyThread(OldThread, Prcb);
341 
342  //
343  // Swap to the new thread
344  // On ARM we call KiSwapContext instead of KiSwapContextInternal,
345  // because we're calling this from C code and not assembly.
346  // This is similar to how it gets called for unwaiting, on x86
347  //
348  KiSwapContext(OldThread, NewThread);
349  }
350 }
351 #endif
352 
353 VOID
355  IN ULONG Reserved)
356 {
357  KIRQL OldIrql, Irql;
358  ULONG InterruptCause;//, InterruptMask;
359  PKIPCR Pcr;
360  PKTRAP_FRAME OldTrapFrame;
361  ASSERT(TrapFrame->Reserved == 0xBADB0D00);
362 
363  //
364  // Increment interrupt count
365  //
366  Pcr = (PKIPCR)KeGetPcr();
367  Pcr->Prcb.InterruptCount++;
368 
369  //
370  // Get the old IRQL
371  //
373  TrapFrame->PreviousIrql = OldIrql;
374 
375  //
376  // Get the interrupt source
377  //
378  InterruptCause = HalGetInterruptSource();
379  //DPRINT1("[INT] (%x) @ %p %p\n", InterruptCause, TrapFrame->SvcLr, TrapFrame->Pc);
380 
381  //
382  // Get the new IRQL and Interrupt Mask
383  //
385  //Irql = Pcr->IrqlMask[InterruptCause];
386  //InterruptMask = Pcr->IrqlTable[Irql];
387  Irql = 0;
388  __debugbreak();
389 
390  //
391  // Raise to the new IRQL
392  //
393  KfRaiseIrql(Irql);
394 
395  //
396  // The clock ISR wants the trap frame as a parameter
397  //
398  OldTrapFrame = KeGetCurrentThread()->TrapFrame;
399  KeGetCurrentThread()->TrapFrame = TrapFrame;
400 
401  //
402  // Check if this interrupt is at DISPATCH or higher
403  //
404  if (Irql > DISPATCH_LEVEL)
405  {
406  //
407  // FIXME-TODO: Switch to interrupt stack
408  //
409  //DPRINT1("[ISR]\n");
410  }
411  else
412  {
413  //
414  // We know this is APC or DPC.
415  //
416  //DPRINT1("[DPC/APC]\n");
418  }
419 
420  //
421  // Call the registered interrupt routine
422  //
424  //Pcr->InterruptRoutine[Irql]();
425  __debugbreak();
426  ASSERT(KeGetCurrentThread()->TrapFrame == TrapFrame);
427  KeGetCurrentThread()->TrapFrame = OldTrapFrame;
428 // DPRINT1("[ISR RETURN]\n");
429 
430  //
431  // Restore IRQL and interrupts
432  //
434  _enable();
435 }
436 
437 NTSTATUS
439 {
441  ASSERT(TrapFrame->Reserved == 0xBADB0D00);
442  ULONG Instruction = *(PULONG)TrapFrame->Pc;
443  ULONG DebugType, Parameter0;
444  EXCEPTION_RECORD ExceptionRecord;
445 
446  DPRINT1("[PREFETCH ABORT] (%x) @ %p/%p/%p\n",
447  KeArmInstructionFaultStatusRegisterGet(), Address, TrapFrame->Lr, TrapFrame->Pc);
448  while (TRUE);
449 
450  //
451  // What we *SHOULD* do is look at the instruction fault status register
452  // and see if it's equal to 2 (debug trap). Unfortunately QEMU doesn't seem
453  // to emulate this behaviour properly, so we use a workaround.
454  //
455  //if (KeArmInstructionFaultStatusRegisterGet() == 2)
456  if (Instruction & 0xE1200070) // BKPT
457  {
458  //
459  // Okay, we know this is a breakpoint, extract the index
460  //
461  DebugType = Instruction & 0xF;
462  if (DebugType == BREAKPOINT_PRINT)
463  {
464  //
465  // Debug Service
466  //
467  Parameter0 = TrapFrame->R0;
468  TrapFrame->Pc += sizeof(ULONG);
469  }
470  else
471  {
472  //
473  // Standard INT3 (emulate x86 behavior)
474  //
475  Parameter0 = STATUS_SUCCESS;
476  }
477 
478  //
479  // Build the exception record
480  //
481  ExceptionRecord.ExceptionCode = STATUS_BREAKPOINT;
482  ExceptionRecord.ExceptionFlags = 0;
483  ExceptionRecord.ExceptionRecord = NULL;
484  ExceptionRecord.ExceptionAddress = (PVOID)TrapFrame->Pc;
485  ExceptionRecord.NumberParameters = 3;
486 
487  //
488  // Build the parameters
489  //
490  ExceptionRecord.ExceptionInformation[0] = Parameter0;
491  ExceptionRecord.ExceptionInformation[1] = TrapFrame->R1;
492  ExceptionRecord.ExceptionInformation[2] = TrapFrame->R2;
493 
494  //
495  // Dispatch the exception
496  //
497  KiDispatchException(&ExceptionRecord,
498  NULL,
499  TrapFrame,
500  KiGetPreviousMode(TrapFrame),
501  TRUE);
502 
503  //
504  // We're done
505  //
506  return STATUS_SUCCESS;
507  }
508 
509  //
510  // Unhandled
511  //
513  ASSERT(FALSE);
514  return STATUS_SUCCESS;
515 }
516 
517 NTSTATUS
519 {
522  ASSERT(TrapFrame->Reserved == 0xBADB0D00);
523 
524  DPRINT1("[ABORT] (%x) @ %p/%p/%p\n",
525  KeArmFaultStatusRegisterGet(), Address, TrapFrame->Lr, TrapFrame->Pc);
526  while (TRUE);
527 
528  //
529  // Check if this is a page fault
530  //
532  {
534  Address,
535  KiGetPreviousMode(TrapFrame),
536  TrapFrame);
537  if (NT_SUCCESS(Status)) return Status;
538  }
539 
540  //
541  // Unhandled
542  //
544  ASSERT(FALSE);
545  return STATUS_SUCCESS;
546 }
547 
548 VOID
550 {
553  ULONG Instruction;
554  ASSERT(TrapFrame->Reserved == 0xBADB0D00);
555 
556  DPRINT1("[SWI] @ %p/%p\n", TrapFrame->Lr, TrapFrame->Pc);
557  while (TRUE);
558 
559  //
560  // Get the current thread
561  //
563 
564  //
565  // Isolate previous mode
566  //
567  PreviousMode = KiGetPreviousMode(TrapFrame);
568 
569  //
570  // Save old previous mode
571  //
572  TrapFrame->PreviousMode = PreviousMode;
573  TrapFrame->TrapFrame = (ULONG_PTR)Thread->TrapFrame;
574 
575  //
576  // Save previous mode and trap frame
577  //
578  Thread->TrapFrame = TrapFrame;
579  Thread->PreviousMode = PreviousMode;
580 
581  //
582  // Read the opcode
583  //
584  Instruction = *(PULONG)(TrapFrame->Pc - sizeof(ULONG));
585 
586  //
587  // Call the service call dispatcher
588  //
589  KiSystemService(Thread, TrapFrame, Instruction);
590 }
591 
592 NTSTATUS
594 {
595  ASSERT(TrapFrame->Reserved == 0xBADB0D00);
596 
597  //
598  // This should never happen
599  //
600  DPRINT1("[UNDEF] @ %p/%p\n", TrapFrame->Lr, TrapFrame->Pc);
602  ASSERT(FALSE);
603  return STATUS_SUCCESS;
604 }
ULONG HalGetInterruptSource(VOID)
Definition: pic.c:108
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
DECLSPEC_NORETURN VOID KiIdleLoop(VOID)
Definition: stubs.c:172
#define IN
Definition: typedefs.h:39
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
ULONG_PTR DirectoryTableBase
Definition: ketypes.h:2019
NTSTATUS NTAPI MmAccessFault(IN ULONG FaultCode, IN PVOID Address, IN KPROCESSOR_MODE Mode, IN PVOID TrapInformation)
Definition: mmfault.c:205
KDPC_DATA DpcData[2]
Definition: ketypes.h:680
#define TRUE
Definition: types.h:120
void __cdecl _enable(void)
Definition: intrin_arm.h:373
LONG NTSTATUS
Definition: precomp.h:26
struct _KIPCR * PKIPCR
VOID NTAPI KiQuantumEnd(VOID)
Definition: dpc.c:465
Definition: ke.h:289
UCHAR QuantumEnd
Definition: ketypes.h:700
FORCEINLINE ULONG KeArmFaultStatusRegisterGet(VOID)
Definition: intrin_i.h:44
NTSTATUS KiUndefinedExceptionHandler(IN PKTRAP_FRAME TrapFrame)
Definition: trapc.c:593
_Out_ PKIRQL Irql
Definition: csq.h:179
void __cdecl __debugbreak(void)
Definition: intrin_ppc.h:698
struct _KTHREAD * NextThread
Definition: ketypes.h:571
#define DECLSPEC_NORETURN
Definition: ntbasedef.h:176
#define KeGetPcr()
Definition: ke.h:26
FORCEINLINE VOID KeArmWaitForInterrupt(VOID)
Definition: intrin_i.h:215
uint32_t ULONG_PTR
Definition: typedefs.h:65
BOOLEAN FASTCALL KiSwapContext(IN KIRQL WaitIrql, IN PKTHREAD CurrentThread)
UCHAR KIRQL
Definition: env_spec_w32.h:591
FORCEINLINE VOID KxQueueReadyThread(IN PKTHREAD Thread, IN PKPRCB Prcb)
Definition: ke_x.h:1352
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define FALSE
Definition: types.h:117
VOID NTAPI KiDispatchException(PEXCEPTION_RECORD ExceptionRecord, PKEXCEPTION_FRAME ExceptionFrame, PKTRAP_FRAME Tf, KPROCESSOR_MODE PreviousMode, BOOLEAN SearchFrames)
VOID KiSystemService(IN PKTHREAD Thread, IN PKTRAP_FRAME TrapFrame, IN ULONG Instruction)
Definition: stubs.c:399
VOID KiSoftwareInterruptHandler(IN PKTRAP_FRAME TrapFrame)
Definition: trapc.c:549
struct _KTHREAD * CurrentThread
Definition: ketypes.h:570
unsigned char BOOLEAN
static WCHAR Address[46]
Definition: ping.c:68
#define STATUS_BREAKPOINT
Definition: ntstatus.h:184
FORCEINLINE ULONG KeArmFaultAddressRegisterGet(VOID)
Definition: intrin_i.h:70
_Reserved_ PVOID Reserved
Definition: winddi.h:3974
void * PVOID
Definition: retypes.h:9
ULONG InterruptCount
Definition: ketypes.h:736
UCHAR WaitReason
Definition: ketypes.h:1896
KIRQL FASTCALL KfRaiseIrql(IN KIRQL NewIrql)
Definition: pic.c:187
Status
Definition: gdiplustypes.h:24
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103
NTSTATUS KiPrefetchAbortHandler(IN PKTRAP_FRAME TrapFrame)
Definition: trapc.c:438
UINT64 TimerRequest
Definition: ketypes.h:695
#define ASSERT(a)
Definition: mode.c:44
VOID KiInterruptHandler(IN PKTRAP_FRAME TrapFrame, IN ULONG Reserved)
Definition: trapc.c:354
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
VOID NTAPI KiSwapProcess(IN PKPROCESS NewProcess, IN PKPROCESS OldProcess)
Definition: trapc.c:97
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
VOID KiApcInterrupt(VOID)
Definition: trapc.c:229
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
struct _SINGLE_LIST_ENTRY * Next
Definition: ntbasedef.h:629
#define BREAKPOINT_PRINT
Definition: kdtypes.h:51
UCHAR DpcRoutineActive
Definition: ketypes.h:692
KPRCB Prcb
Definition: ketypes.h:893
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:790
VOID NTAPI KiDispatchInterrupt(VOID)
Definition: thrdini.c:295
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
SINGLE_LIST_ENTRY DeferredReadyListHead
Definition: ketypes.h:632
VOID FASTCALL HalRequestSoftwareInterrupt(IN KIRQL Irql)
Definition: pic.c:271
volatile ULONG DpcQueueDepth
Definition: ketypes.h:788
FORCEINLINE ULONG KeArmInstructionFaultStatusRegisterGet(VOID)
Definition: intrin_i.h:57
unsigned int * PULONG
Definition: retypes.h:1
#define NULL
Definition: types.h:112
#define KiGetPreviousMode(tf)
Definition: ke.h:180
#define DPRINT1
Definition: precomp.h:8
ULONG ContextSwitches
Definition: ketypes.h:896
PVOID PerfGlobalGroupMask
Definition: ketypes.h:744
VOID FASTCALL HalClearSoftwareInterrupt(IN KIRQL Irql)
Definition: pic.c:282
volatile UCHAR State
Definition: ketypes.h:1721
void __cdecl _disable(void)
Definition: intrin_arm.h:365
unsigned int ULONG
Definition: retypes.h:1
#define UNIMPLEMENTED
Definition: debug.h:115
#define ULONG_PTR
Definition: config.h:101
struct _KPCR * PKPCR
struct _KTHREAD * CurrentThread
Definition: ketypes.h:551
#define STATUS_SUCCESS
Definition: shellext.h:65
#define KeGetCurrentThread
Definition: hal.h:50
NTSTATUS KiDataAbortHandler(IN PKTRAP_FRAME TrapFrame)
Definition: trapc.c:518
VOID NTAPI KiDeliverApc(IN KPROCESSOR_MODE DeliveryMode, IN PKEXCEPTION_FRAME ExceptionFrame, IN PKTRAP_FRAME TrapFrame)
Definition: apc.c:302
#define APC_LEVEL
Definition: env_spec_w32.h:695
VOID NTAPI KeBugCheckEx(_In_ ULONG BugCheckCode, _In_ ULONG_PTR BugCheckParameter1, _In_ ULONG_PTR BugCheckParameter2, _In_ ULONG_PTR BugCheckParameter3, _In_ ULONG_PTR BugCheckParameter4)
Definition: rtlcompat.c:108
VOID FASTCALL KiRetireDpcList(IN PKPRCB Prcb)
Definition: dpc.c:561
struct _KPRCB * Prcb
Definition: ke.h:20
FORCEINLINE VOID KeArmTranslationTableRegisterSet(IN ARM_TTB_REGISTER Ttb)
Definition: intrin_i.h:145