Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygentrapc.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: BSD - See COPYING.ARM in the top level directory 00004 * FILE: ntoskrnl/ke/arm/trapc.c 00005 * PURPOSE: Implements the various trap handlers for ARM exceptions 00006 * PROGRAMMERS: ReactOS Portable Systems Group 00007 */ 00008 00009 /* INCLUDES *******************************************************************/ 00010 00011 #include <ntoskrnl.h> 00012 #include <internal/arm/ksarm.h> 00013 #define NDEBUG 00014 #include <debug.h> 00015 00016 /* FUNCTIONS ******************************************************************/ 00017 00018 #if 0 00019 VOID 00020 KiIdleLoop(VOID) 00021 { 00022 PKPCR Pcr = (PKPCR)KeGetPcr(); 00023 PKPRCB Prcb = Pcr->Prcb; 00024 PKTHREAD OldThread, NewThread; 00025 00026 // 00027 // Loop forever... that's why this is an idle loop 00028 // 00029 DPRINT1("[IDLE LOOP]\n"); 00030 while (TRUE); 00031 00032 while (TRUE) 00033 { 00034 // 00035 // Cycle interrupts 00036 // 00037 _disable(); 00038 _enable(); 00039 00040 // 00041 // Check if there's DPC work to do 00042 // 00043 if ((Prcb->DpcData[0].DpcQueueDepth) || 00044 (Prcb->TimerRequest) || 00045 (Prcb->DeferredReadyListHead.Next)) 00046 { 00047 // 00048 // Clear the pending interrupt 00049 // 00050 HalClearSoftwareInterrupt(DISPATCH_LEVEL); 00051 00052 // 00053 // Retire DPCs 00054 // 00055 KiRetireDpcList(Prcb); 00056 } 00057 00058 // 00059 // Check if there's a thread to schedule 00060 // 00061 if (Prcb->NextThread) 00062 { 00063 // 00064 // Out with the old, in with the new... 00065 // 00066 OldThread = Prcb->CurrentThread; 00067 NewThread = Prcb->NextThread; 00068 Prcb->CurrentThread = NewThread; 00069 Prcb->NextThread = NULL; 00070 00071 // 00072 // Update thread state 00073 // 00074 NewThread->State = Running; 00075 00076 // 00077 // Swap to the new thread 00078 // On ARM we call KiSwapContext instead of KiSwapContextInternal, 00079 // because we're calling this from C code and not assembly. 00080 // This is similar to how it gets called for unwaiting, on x86 00081 // 00082 KiSwapContext(OldThread, NewThread); 00083 } 00084 else 00085 { 00086 // 00087 // Go into WFI (sleep more) 00088 // 00089 KeArmWaitForInterrupt(); 00090 } 00091 } 00092 } 00093 #endif 00094 00095 VOID 00096 NTAPI 00097 KiSwapProcess(IN PKPROCESS NewProcess, 00098 IN PKPROCESS OldProcess) 00099 { 00100 ARM_TTB_REGISTER TtbRegister; 00101 DPRINT1("Swapping from: %p (%16s) to %p (%16s)\n", 00102 OldProcess, ((PEPROCESS)OldProcess)->ImageFileName, 00103 NewProcess, ((PEPROCESS)NewProcess)->ImageFileName); 00104 00105 // 00106 // Update the page directory base 00107 // 00108 TtbRegister.AsUlong = NewProcess->DirectoryTableBase[0]; 00109 ASSERT(TtbRegister.Reserved == 0); 00110 KeArmTranslationTableRegisterSet(TtbRegister); 00111 00112 // 00113 // FIXME: Flush the TLB 00114 // 00115 00116 00117 DPRINT1("Survived!\n"); 00118 while (TRUE); 00119 } 00120 00121 #if 0 00122 BOOLEAN 00123 KiSwapContextInternal(IN PKTHREAD OldThread, 00124 IN PKTHREAD NewThread) 00125 { 00126 PKIPCR Pcr = (PKIPCR)KeGetPcr(); 00127 PKPRCB Prcb = Pcr->Prcb; 00128 PKPROCESS OldProcess, NewProcess; 00129 00130 DPRINT1("SWAP\n"); 00131 while (TRUE); 00132 00133 // 00134 // Increase context switch count 00135 // 00136 Pcr->ContextSwitches++; 00137 00138 // 00139 // Check if WMI tracing is enabled 00140 // 00141 if (Pcr->PerfGlobalGroupMask) 00142 { 00143 // 00144 // We don't support this yet on x86 either 00145 // 00146 DPRINT1("WMI Tracing not supported\n"); 00147 ASSERT(FALSE); 00148 } 00149 00150 // 00151 // Check if the processes are also different 00152 // 00153 OldProcess = OldThread->ApcState.Process; 00154 NewProcess = NewThread->ApcState.Process; 00155 if (OldProcess != NewProcess) 00156 { 00157 // 00158 // Check if address space switch is needed 00159 // 00160 if (OldProcess->DirectoryTableBase[0] != 00161 NewProcess->DirectoryTableBase[0]) 00162 { 00163 // 00164 // FIXME-USER: Support address space switch 00165 // 00166 DPRINT1("Address space switch not implemented\n"); 00167 ASSERT(FALSE); 00168 } 00169 } 00170 00171 // 00172 // Increase thread context switches 00173 // 00174 NewThread->ContextSwitches++; 00175 #if 0 // I don't buy this 00176 // 00177 // Set us as the current thread 00178 // NOTE: On RISC Platforms, there is both a KPCR CurrentThread, and a 00179 // KPRCB CurrentThread. 00180 // The latter is set just like on x86-based builds, the former is only set 00181 // when actually doing the context switch (here). 00182 // Recall that the reason for the latter is due to the fact that the KPCR 00183 // is shared with user-mode (read-only), so that information is exposed 00184 // there as well. 00185 // 00186 Pcr->CurrentThread = NewThread; 00187 #endif 00188 // 00189 // DPCs shouldn't be active 00190 // 00191 if (Prcb->DpcRoutineActive) 00192 { 00193 // 00194 // Crash the machine 00195 // 00196 KeBugCheckEx(ATTEMPTED_SWITCH_FROM_DPC, 00197 (ULONG_PTR)OldThread, 00198 (ULONG_PTR)NewThread, 00199 (ULONG_PTR)OldThread->InitialStack, 00200 0); 00201 } 00202 00203 // 00204 // Kernel APCs may be pending 00205 // 00206 if (NewThread->ApcState.KernelApcPending) 00207 { 00208 // 00209 // Are APCs enabled? 00210 // 00211 if (NewThread->SpecialApcDisable == 0) 00212 { 00213 // 00214 // Request APC delivery 00215 // 00216 HalRequestSoftwareInterrupt(APC_LEVEL); 00217 return TRUE; 00218 } 00219 } 00220 00221 // 00222 // Return 00223 // 00224 return FALSE; 00225 } 00226 #endif 00227 00228 VOID 00229 KiApcInterrupt(VOID) 00230 { 00231 KPROCESSOR_MODE PreviousMode; 00232 KEXCEPTION_FRAME ExceptionFrame; 00233 PKTRAP_FRAME TrapFrame = KeGetCurrentThread()->TrapFrame; 00234 00235 DPRINT1("[APC TRAP]\n"); 00236 while (TRUE); 00237 00238 // 00239 // Isolate previous mode 00240 // 00241 PreviousMode = KiGetPreviousMode(TrapFrame); 00242 00243 // 00244 // FIXME-USER: Handle APC interrupt while in user-mode 00245 // 00246 if (PreviousMode == UserMode) ASSERT(FALSE); 00247 00248 // 00249 // Disable interrupts 00250 // 00251 _disable(); 00252 00253 // 00254 // Clear APC interrupt 00255 // 00256 HalClearSoftwareInterrupt(APC_LEVEL); 00257 00258 // 00259 // Re-enable interrupts 00260 // 00261 _enable(); 00262 00263 // 00264 // Deliver APCs 00265 // 00266 KiDeliverApc(PreviousMode, &ExceptionFrame, TrapFrame); 00267 } 00268 00269 #if 0 00270 VOID 00271 KiDispatchInterrupt(VOID) 00272 { 00273 PKIPCR Pcr; 00274 PKPRCB Prcb; 00275 PKTHREAD NewThread, OldThread; 00276 00277 DPRINT1("[DPC TRAP]\n"); 00278 while (TRUE); 00279 00280 // 00281 // Get the PCR and disable interrupts 00282 // 00283 Pcr = (PKIPCR)KeGetPcr(); 00284 Prcb = Pcr->Prcb; 00285 _disable(); 00286 00287 // 00288 //Check if we have to deliver DPCs, timers, or deferred threads 00289 // 00290 if ((Prcb->DpcData[0].DpcQueueDepth) || 00291 (Prcb->TimerRequest) || 00292 (Prcb->DeferredReadyListHead.Next)) 00293 { 00294 // 00295 // Retire DPCs 00296 // 00297 KiRetireDpcList(Prcb); 00298 } 00299 00300 // 00301 // Re-enable interrupts 00302 // 00303 _enable(); 00304 00305 // 00306 // Check for quantum end 00307 // 00308 if (Prcb->QuantumEnd) 00309 { 00310 // 00311 // Handle quantum end 00312 // 00313 Prcb->QuantumEnd = FALSE; 00314 KiQuantumEnd(); 00315 return; 00316 } 00317 00318 // 00319 // Check if we have a thread to swap to 00320 // 00321 if (Prcb->NextThread) 00322 { 00323 // 00324 // Next is now current 00325 // 00326 OldThread = Prcb->CurrentThread; 00327 NewThread = Prcb->NextThread; 00328 Prcb->CurrentThread = NewThread; 00329 Prcb->NextThread = NULL; 00330 00331 // 00332 // Update thread states 00333 // 00334 NewThread->State = Running; 00335 OldThread->WaitReason = WrDispatchInt; 00336 00337 // 00338 // Make the old thread ready 00339 // 00340 KxQueueReadyThread(OldThread, Prcb); 00341 00342 // 00343 // Swap to the new thread 00344 // On ARM we call KiSwapContext instead of KiSwapContextInternal, 00345 // because we're calling this from C code and not assembly. 00346 // This is similar to how it gets called for unwaiting, on x86 00347 // 00348 KiSwapContext(OldThread, NewThread); 00349 } 00350 } 00351 #endif 00352 00353 VOID 00354 KiInterruptHandler(IN PKTRAP_FRAME TrapFrame, 00355 IN ULONG Reserved) 00356 { 00357 KIRQL OldIrql, Irql; 00358 ULONG InterruptCause, InterruptMask; 00359 PKIPCR Pcr; 00360 PKTRAP_FRAME OldTrapFrame; 00361 ASSERT(TrapFrame->DbgArgMark == 0xBADB0D00); 00362 00363 // 00364 // Increment interrupt count 00365 // 00366 Pcr = (PKIPCR)KeGetPcr(); 00367 Pcr->Prcb->InterruptCount++; 00368 00369 // 00370 // Get the old IRQL 00371 // 00372 OldIrql = KeGetCurrentIrql(); 00373 TrapFrame->OldIrql = OldIrql; 00374 00375 // 00376 // Get the interrupt source 00377 // 00378 InterruptCause = HalGetInterruptSource(); 00379 //DPRINT1("[INT] (%x) @ %p %p\n", InterruptCause, TrapFrame->SvcLr, TrapFrame->Pc); 00380 00381 // 00382 // Get the new IRQL and Interrupt Mask 00383 // 00384 Irql = Pcr->IrqlMask[InterruptCause]; 00385 InterruptMask = Pcr->IrqlTable[Irql]; 00386 00387 // 00388 // Raise to the new IRQL 00389 // 00390 KfRaiseIrql(Irql); 00391 00392 // 00393 // The clock ISR wants the trap frame as a parameter 00394 // 00395 OldTrapFrame = KeGetCurrentThread()->TrapFrame; 00396 KeGetCurrentThread()->TrapFrame = TrapFrame; 00397 00398 // 00399 // Check if this interrupt is at DISPATCH or higher 00400 // 00401 if (Irql > DISPATCH_LEVEL) 00402 { 00403 // 00404 // FIXME-TODO: Switch to interrupt stack 00405 // 00406 //DPRINT1("[ISR]\n"); 00407 } 00408 else 00409 { 00410 // 00411 // We know this is APC or DPC. 00412 // 00413 //DPRINT1("[DPC/APC]\n"); 00414 HalClearSoftwareInterrupt(Irql); 00415 } 00416 00417 // 00418 // Call the registered interrupt routine 00419 // 00420 Pcr->InterruptRoutine[Irql](); 00421 ASSERT(KeGetCurrentThread()->TrapFrame == TrapFrame); 00422 KeGetCurrentThread()->TrapFrame = OldTrapFrame; 00423 // DPRINT1("[ISR RETURN]\n"); 00424 00425 // 00426 // Restore IRQL and interrupts 00427 // 00428 KeLowerIrql(OldIrql); 00429 _enable(); 00430 } 00431 00432 NTSTATUS 00433 KiPrefetchAbortHandler(IN PKTRAP_FRAME TrapFrame) 00434 { 00435 PVOID Address = (PVOID)KeArmFaultAddressRegisterGet(); 00436 ASSERT(TrapFrame->DbgArgMark == 0xBADB0D00); 00437 ULONG Instruction = *(PULONG)TrapFrame->Pc; 00438 ULONG DebugType, Parameter0; 00439 EXCEPTION_RECORD ExceptionRecord; 00440 00441 DPRINT1("[PREFETCH ABORT] (%x) @ %p/%p/%p\n", 00442 KeArmInstructionFaultStatusRegisterGet(), Address, TrapFrame->SvcLr, TrapFrame->Pc); 00443 while (TRUE); 00444 00445 // 00446 // What we *SHOULD* do is look at the instruction fault status register 00447 // and see if it's equal to 2 (debug trap). Unfortunately QEMU doesn't seem 00448 // to emulate this behaviour properly, so we use a workaround. 00449 // 00450 //if (KeArmInstructionFaultStatusRegisterGet() == 2) 00451 if (Instruction & 0xE1200070) // BKPT 00452 { 00453 // 00454 // Okay, we know this is a breakpoint, extract the index 00455 // 00456 DebugType = Instruction & 0xF; 00457 if (DebugType == BREAKPOINT_PRINT) 00458 { 00459 // 00460 // Debug Service 00461 // 00462 Parameter0 = TrapFrame->R0; 00463 TrapFrame->Pc += sizeof(ULONG); 00464 } 00465 else 00466 { 00467 // 00468 // Standard INT3 (emulate x86 behavior) 00469 // 00470 Parameter0 = STATUS_SUCCESS; 00471 } 00472 00473 // 00474 // Build the exception record 00475 // 00476 ExceptionRecord.ExceptionCode = STATUS_BREAKPOINT; 00477 ExceptionRecord.ExceptionFlags = 0; 00478 ExceptionRecord.ExceptionRecord = NULL; 00479 ExceptionRecord.ExceptionAddress = (PVOID)TrapFrame->Pc; 00480 ExceptionRecord.NumberParameters = 3; 00481 00482 // 00483 // Build the parameters 00484 // 00485 ExceptionRecord.ExceptionInformation[0] = Parameter0; 00486 ExceptionRecord.ExceptionInformation[1] = TrapFrame->R1; 00487 ExceptionRecord.ExceptionInformation[2] = TrapFrame->R2; 00488 00489 // 00490 // Dispatch the exception 00491 // 00492 KiDispatchException(&ExceptionRecord, 00493 NULL, 00494 TrapFrame, 00495 KiGetPreviousMode(TrapFrame), 00496 TRUE); 00497 00498 // 00499 // We're done 00500 // 00501 return STATUS_SUCCESS; 00502 } 00503 00504 // 00505 // Unhandled 00506 // 00507 UNIMPLEMENTED; 00508 ASSERT(FALSE); 00509 return STATUS_SUCCESS; 00510 } 00511 00512 NTSTATUS 00513 KiDataAbortHandler(IN PKTRAP_FRAME TrapFrame) 00514 { 00515 NTSTATUS Status; 00516 PVOID Address = (PVOID)KeArmFaultAddressRegisterGet(); 00517 ASSERT(TrapFrame->DbgArgMark == 0xBADB0D00); 00518 00519 DPRINT1("[ABORT] (%x) @ %p/%p/%p\n", 00520 KeArmFaultStatusRegisterGet(), Address, TrapFrame->SvcLr, TrapFrame->Pc); 00521 while (TRUE); 00522 00523 // 00524 // Check if this is a page fault 00525 // 00526 if (KeArmFaultStatusRegisterGet() == 21 || KeArmFaultStatusRegisterGet() == 23) 00527 { 00528 Status = MmAccessFault(FALSE, 00529 Address, 00530 KiGetPreviousMode(TrapFrame), 00531 TrapFrame); 00532 if (NT_SUCCESS(Status)) return Status; 00533 } 00534 00535 // 00536 // Unhandled 00537 // 00538 UNIMPLEMENTED; 00539 ASSERT(FALSE); 00540 return STATUS_SUCCESS; 00541 } 00542 00543 VOID 00544 KiSoftwareInterruptHandler(IN PKTRAP_FRAME TrapFrame) 00545 { 00546 PKTHREAD Thread; 00547 KPROCESSOR_MODE PreviousMode; 00548 ULONG Instruction; 00549 ASSERT(TrapFrame->DbgArgMark == 0xBADB0D00); 00550 00551 DPRINT1("[SWI] @ %p/%p\n", TrapFrame->SvcLr, TrapFrame->Pc); 00552 while (TRUE); 00553 00554 // 00555 // Get the current thread 00556 // 00557 Thread = KeGetCurrentThread(); 00558 00559 // 00560 // Isolate previous mode 00561 // 00562 PreviousMode = KiGetPreviousMode(TrapFrame); 00563 00564 // 00565 // Save old previous mode 00566 // 00567 TrapFrame->PreviousMode = PreviousMode; 00568 TrapFrame->PreviousTrapFrame = (ULONG_PTR)Thread->TrapFrame; 00569 00570 // 00571 // Save previous mode and trap frame 00572 // 00573 Thread->TrapFrame = TrapFrame; 00574 Thread->PreviousMode = PreviousMode; 00575 00576 // 00577 // Read the opcode 00578 // 00579 Instruction = *(PULONG)(TrapFrame->Pc - sizeof(ULONG)); 00580 00581 // 00582 // Call the service call dispatcher 00583 // 00584 KiSystemService(Thread, TrapFrame, Instruction); 00585 } 00586 00587 NTSTATUS 00588 KiUndefinedExceptionHandler(IN PKTRAP_FRAME TrapFrame) 00589 { 00590 ASSERT(TrapFrame->DbgArgMark == 0xBADB0D00); 00591 00592 // 00593 // This should never happen 00594 // 00595 DPRINT1("[UNDEF] @ %p/%p\n", TrapFrame->SvcLr, TrapFrame->Pc); 00596 UNIMPLEMENTED; 00597 ASSERT(FALSE); 00598 return STATUS_SUCCESS; 00599 } Generated on Sun May 27 2012 04:37:31 for ReactOS by
1.7.6.1
|