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