/*++ Copyright (c) 2012 Minoca Corp. All Rights Reserved Module Name: trap.S Abstract: This module implements interrupt and exception trap management, such as saving and restoring registers. Author: Evan Green 11-Aug-2012 Environment: Kernel mode --*/ ## ## ------------------------------------------------------------------- Includes ## #include ## ## ---------------------------------------------------------------- Definitions ## ## ## ---------------------------------------------------------------------- Code ## ASSEMBLY_FILE_HEADER ## ## VOID ## ArpInitializeExceptionStacks ( ## PVOID ExceptionStacksBase, ## ULONG ExceptionStackSize ## ) ## /*++ Routine Description: This routine initializes the stack pointer for all privileged ARM modes. It switches into each mode and initializes the banked r13. This function should be called with interrupts disabled and returns with interrupts disabled. Arguments: ExceptionStacksBase - Supplies a pointer to the lowest address that should be used for exception stacks. Each stack takes up 16 bytes and there are 4 modes, so at least 64 bytes are needed. ExceptionStackSize - Supplies the size of each exception stack. Return Value: None. --*/ FUNCTION ArpInitializeExceptionStacks ## ## Load R1 with an individual stack size. ## add %r0, %r0, %r1 ## ## Disable interrupts and switch into IRQ mode. Note that this also ## clobbers the flags register. ## mov %r2, #(PSR_FLAG_IRQ | ARM_MODE_IRQ) msr CPSR_cxsf, %r2 mov %sp, %r0 add %r0, %r0, %r1 ## ## Initialize the FIQ stack. ## mov %r2, #(PSR_FLAG_IRQ | ARM_MODE_FIQ) msr CPSR_cxsf, %r2 mov %sp, %r0 add %r0, %r0, %r1 ## ## Initialize the undefined instruction stack. ## mov %r2, #(PSR_FLAG_IRQ | ARM_MODE_UNDEF) msr CPSR_cxsf, %r2 mov %sp, %r0 add %r0, %r0, %r1 ## ## Initialize the data fetch abort stack. ## mov %r2, #(PSR_FLAG_IRQ | ARM_MODE_ABORT) msr CPSR_cxsf, %r2 mov %sp, %r0 ## ## Switch back to SVC mode and return. ## mov %r2, #(PSR_FLAG_IRQ | ARM_MODE_SVC) msr CPSR_cxsf, %r2 bx %lr END_FUNCTION ArpInitializeExceptionStacks ## ## VOID ## ArpUndefinedInstructionEntry ( ## VOID ## ) ## /*++ Routine Description: This routine directly handles an exception generated by an undefined instruction. It uses a largely separate code path from normal exceptions to avoid recursively breaking into the debugger. Arguments: None. Return Value: None. --*/ FUNCTION ArpUndefinedInstructionEntry ## ## Save state and create a trap frame. ## ARM_ENTER_INTERRUPT ## ## Call the main dispatch routine routine with a pointer to the trap frame ## as the only parameter. Align the stack down even though it shouldn't be ## strictly necessary in case something bad happened. ## mov %r0, %sp mov %r4, %sp and %r1, %r4, #0xFFFFFFF0 @ Align stack down for fear of badness. mov %sp, %r1 bl KeDispatchUndefinedInstructionException mov %sp, %r4 ## ## Restore state and return. ## ARM_EXIT_INTERRUPT END_FUNCTION ArpUndefinedInstructionEntry ## ## VOID ## ArpSoftwareInterruptEntry ( ## VOID ## ) ## /*++ Routine Description: This routine directly handles an exception generated by a software interrupt (a system call). Arguments: None. Return Value: None. --*/ FUNCTION ArpSoftwareInterruptEntry srsdb %sp!, #ARM_MODE_SVC @ Push lr and spsr. mov %lr, #0 @ Zero SVC link register. stmdb %sp!, {%r1-%r12, %lr} @ Push general registers. mrs %r2, cpsr @ Get the "exception" CPSR. stmdb %sp!, {%r0, %r2} @ Push exception CPSR and R0. mov %r4, %sp @ Get stack. sub %sp, #8 @ Account for pushes. cps #ARM_MODE_SYSTEM @ Switch to system mode. str %lr, [%r4, #-4] @ Save usermode SP. str %sp, [%r4, #-8] @ Save usermode LR. cpsie i, #ARM_MODE_SVC @ Enable interrupts, svc mode. sub %sp, #4 @ Allocate room for sp. str %sp, [%sp] @ Save SP. ## ## The system call routine takes three parameters: the system call number, ## system call parameter, and a pointer to the trap frame. User-mode already ## set up the first two parameters in R0 and R1, and they were preserved ## throughout the context save process here. So all that's left is to put a ## pointer to the trap frame in R2. ## mov %r2, %sp bl KeSystemCallHandler ## ## Restore state and return. ## ARM_EXIT_INTERRUPT END_FUNCTION ArpSoftwareInterruptEntry ## ## VOID ## ArpPrefetchAbortEntry ( ## VOID ## ) ## /*++ Routine Description: This routine directly handles an exception generated by a prefetch abort (page fault). Arguments: None. Return Value: None. --*/ FUNCTION ArpPrefetchAbortEntry ## ## In ARM mode, prefect aborts save the PC-4 in LR. For Thumb mode, data ## aborts save the PC in LR. Thus, the PC is always 4 bytes head of the ## faulting address. ## sub %lr, %lr, #4 @ Prefetches go too far by 4. ## ## Save state and create a trap frame. ## ARM_ENTER_INTERRUPT ## ## Call the main dispatch routine routine with a pointer to the trap frame ## and 1 to indicate a prefetch abort. ## mov %r0, %sp mov %r1, #1 blx KeDispatchException ## ## Restore state and return. ## ARM_EXIT_INTERRUPT END_FUNCTION ArpPrefetchAbortEntry ## ## VOID ## ArpDataAbortEntry ( ## VOID ## ) ## /*++ Routine Description: This routine directly handles an exception generated by a data abort (page fault). Arguments: None. Return Value: None. --*/ FUNCTION ArpDataAbortEntry ## ## In ARM mode, data aborts save the PC in LR. For Thumb mode, data aborts ## save the PC+4 in LR. Thus, the PC is always 8 bytes head of the faulting ## address. ## sub %lr, %lr, #8 ## ## Save state and create a trap frame. ## ARM_ENTER_INTERRUPT ## ## Call the main dispatch routine routine with a pointer to the trap frame ## and 0 to indicate a prefetch abort. ## mov %r0, %sp mov %r1, #0 blx KeDispatchException ## ## Restore state and return. ## ARM_EXIT_INTERRUPT END_FUNCTION ArpDataAbortEntry ## ## VOID ## ArpIrqEntry ( ## VOID ## ) ## /*++ Routine Description: This routine directly handles an exception generated by an external interrupt on the IRQ pin. Arguments: None. Return Value: None. --*/ FUNCTION ArpIrqEntry b ArpCommonInterruptEntry END_FUNCTION ArpIrqEntry ## ## VOID ## ArpFiqEntry ( ## VOID ## ) ## /*++ Routine Description: This routine directly handles an exception generated by an external interrupt on the FIQ pin. Arguments: None. Return Value: None. --*/ FUNCTION ArpFiqEntry b ArpCommonInterruptEntry END_FUNCTION ArpFiqEntry ## ## --------------------------------------------------------- Internal Functions ## ## ## This code is entered as the result of any interrupt or exception. Its job is ## to transition back to the SVC stack and then call the real interrupt ## dispatch routine. ## ArpCommonInterruptEntry: ## ## Save state and create a trap frame. ## ARM_ENTER_INTERRUPT ## ## Call the main dispatch routine routine with a pointer to the trap frame ## as the only parameter. Align the stack down in case the exception ## interrupted something unaligned. ## mov %r0, %sp mov %r4, %sp and %r5, %r4, #0xFFFFFFF0 mov %sp, %r5 bl KeDispatchException mov %sp, %r4 ## ## Restore state and return. ## ARM_EXIT_INTERRUPT