ofw_irq.S revision 1.14
11.14Smatt/* $NetBSD: ofw_irq.S,v 1.14 2013/08/18 06:28:18 matt Exp $ */ 21.1Sthorpej 31.1Sthorpej/* 41.1Sthorpej * Copyright (c) 1994-1998 Mark Brinicombe. 51.1Sthorpej * Copyright (c) 1994 Brini. 61.1Sthorpej * All rights reserved. 71.1Sthorpej * 81.1Sthorpej * This code is derived from software written for Brini by Mark Brinicombe 91.1Sthorpej * 101.1Sthorpej * Redistribution and use in source and binary forms, with or without 111.1Sthorpej * modification, are permitted provided that the following conditions 121.1Sthorpej * are met: 131.1Sthorpej * 1. Redistributions of source code must retain the above copyright 141.1Sthorpej * notice, this list of conditions and the following disclaimer. 151.1Sthorpej * 2. Redistributions in binary form must reproduce the above copyright 161.1Sthorpej * notice, this list of conditions and the following disclaimer in the 171.1Sthorpej * documentation and/or other materials provided with the distribution. 181.1Sthorpej * 3. All advertising materials mentioning features or use of this software 191.1Sthorpej * must display the following acknowledgement: 201.1Sthorpej * This product includes software developed by Mark Brinicombe 211.1Sthorpej * for the NetBSD Project. 221.1Sthorpej * 4. The name of the company nor the name of the author may be used to 231.1Sthorpej * endorse or promote products derived from this software without specific 241.1Sthorpej * prior written permission. 251.1Sthorpej * 261.1Sthorpej * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 271.1Sthorpej * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 281.1Sthorpej * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 291.1Sthorpej * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 301.1Sthorpej * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 311.1Sthorpej * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 321.1Sthorpej * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 331.1Sthorpej * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 341.1Sthorpej * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 351.1Sthorpej * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 361.1Sthorpej * 371.1Sthorpej * Low level irq and fiq handlers 381.1Sthorpej * 391.1Sthorpej * Created : 27/09/94 401.1Sthorpej */ 411.1Sthorpej 421.1Sthorpej#include "assym.h" 431.14Smatt#include <arm/asm.h> 441.14Smatt#include <arm/locore.h> 451.14Smatt 461.1Sthorpej#include <machine/irqhandler.h> 471.1Sthorpej 481.1Sthorpej .text 491.1Sthorpej .align 0 501.1Sthorpej 511.1Sthorpej/* 521.1Sthorpej * 531.1Sthorpej * irq_entry 541.1Sthorpej * 551.1Sthorpej * Main entry point for the IRQ vector 561.1Sthorpej * 571.1Sthorpej * This function is called only on timer ticks, passed on to the 581.1Sthorpej * kernel from the OFW tick handler. 591.1Sthorpej * 601.1Sthorpej * For now, I am trying to re-use as much of the code from the 611.1Sthorpej * IOMD interrupt-handler as possible. In time, I will strip this 621.1Sthorpej * down to something OFW-specific. 631.1Sthorpej * 641.1Sthorpej * Here's the original, IOMD-specific description: 651.1Sthorpej * This function reads the irq request bits in the IOMD registers 661.1Sthorpej * IRQRQA, IRQRQB and DMARQ 671.1Sthorpej * It then calls an installed handler for each bit that is set. 681.1Sthorpej * The function stray_irqhandler is called if a handler is not defined 691.1Sthorpej * for a particular interrupt. 701.1Sthorpej * If a interrupt handler is found then it is called with r0 containing 711.1Sthorpej * the argument defined in the handler structure. If the field ih_arg 721.1Sthorpej * is zero then a pointer to the IRQ frame on the stack is passed instead. 731.1Sthorpej */ 741.1Sthorpej 751.1SthorpejLdisabled_mask: 761.1Sthorpej .word _C_LABEL(disabled_mask) 771.1Sthorpej 781.1SthorpejLspl_masks: 791.1Sthorpej .word _C_LABEL(spl_masks) 801.1Sthorpej 811.1SthorpejLofw_ticktmp: 821.1Sthorpej .word _C_LABEL(ofw_ticktmp) 831.1Sthorpej 841.1SthorpejLirq_entry: 851.1Sthorpej .word irq_entry 861.1Sthorpej 871.1SthorpejLofwirqstk: /* hack */ 881.1Sthorpej .word ofwirqstk + 4096 891.1Sthorpej 901.7SthorpejLOCK_CAS_CHECK_LOCALS 911.7Sthorpej 921.3SscwAST_ALIGNMENT_FAULT_LOCALS 931.3Sscw 941.1Sthorpej/* 951.1Sthorpej * Regsister usage 961.1Sthorpej * 971.13Smatt * r4 - Address of cpu_info (on entry) 981.13Smatt * r5 - Pointer to handler pointer list 991.1Sthorpej * r6 - Address of current handler 1001.13Smatt * r7 - pspr mode (must be preserved) 1011.1Sthorpej * r8 - Current IRQ requests. 1021.1Sthorpej * r9 - Used to count through possible IRQ bits. 1031.1Sthorpej * r10 - Base address of IOMD 1041.1Sthorpej */ 1051.1Sthorpej 1061.1SthorpejASENTRY_NP(irq_entry) 1071.1Sthorpej /* 1081.1Sthorpej * We come here following an OFW-handled timer tick. 1091.1Sthorpej * 1101.1Sthorpej * We are in the SVC frame, and interrupts are disabled. 1111.1Sthorpej * The state of the interrupted context is partially in 1121.1Sthorpej * the registers and partially in the global storage area 1131.1Sthorpej * labeled ofw_ticktmp. ofw_ticktmp is filled-in by the 1141.1Sthorpej * tick callback that is invoked by OFW on the way out of 1151.1Sthorpej * its interrupt handler. ofw_ticktmp contains the following: 1161.1Sthorpej * 1171.1Sthorpej * pc // interrupted instruction 1181.1Sthorpej * lr_usr 1191.1Sthorpej * sp_usr 1201.1Sthorpej * r1 // makes r1 available for scratch 1211.1Sthorpej * r0 // makes r0 available for scratch 1221.1Sthorpej * spsr_svc // cpsr of interrupted context 1231.1Sthorpej * 1241.1Sthorpej * The prologue of this routine must re-construct the 1251.1Sthorpej * machine state that existed at the time OFW's interrupt- 1261.1Sthorpej * handler fielded the interrupt. That allows us to use 1271.1Sthorpej * the rest of the code in this routine, and have it all 1281.1Sthorpej * "just work." 1291.1Sthorpej */ 1301.1Sthorpej 1311.1Sthorpej /* 1321.1Sthorpej * Switch to IRQ mode. 1331.1Sthorpej * First check the spsr in ofw_ticktmp to see what the FIQ bit should be. 1341.1Sthorpej * 1351.1Sthorpej * I need 2 scratch registers to do this. 1361.1Sthorpej * Fortunately, r0 and r1 are already saved in ofw_ticktmp. 1371.1Sthorpej * How convenient. 1381.1Sthorpej */ 1391.1Sthorpej ldr r0, Lofw_ticktmp 1401.1Sthorpej ldr r0, [r0] 1411.1Sthorpej and r0, r0, #F32_bit 1421.1Sthorpej mov r1, #(I32_bit | PSR_IRQ32_MODE) 1431.1Sthorpej orr r1, r1, r0 1441.1Sthorpej msr cpsr_all, r1 1451.1Sthorpej 1461.1Sthorpej /* Now we're in IRQ mode. */ 1471.1Sthorpej /* Restore contents of ofw_ticktmp. */ 1481.2Sbjh21 adr r0, Lofwirqstk /* Bummer! Mitch hasn't left me a stack. */ 1491.2Sbjh21 ldr sp, [r0] /* I'll use my own for now... */ 1501.1Sthorpej ldr r0, Lofw_ticktmp /* r0 now points to ofw_ticktmp[0] */ 1511.1Sthorpej ldr r1, [r0], #(4*3) /* skip over saved {r0, r1} */ 1521.1Sthorpej msr spsr_all, r1 /* restore spsr */ 1531.1Sthorpej ldmia r0, {sp, lr}^ /* restore user sp and lr */ 1541.1Sthorpej add r0, r0, #(4*2) /* previous instruction can't writeback */ 1551.1Sthorpej /* this one can't use banked registers */ 1561.1Sthorpej ldr lr, [r0], #(-4*4) /* restore pc; point r0 at ofw_ticktmp[1] */ 1571.1Sthorpej add lr, lr, #4 /* pc += 4; will be decremented below */ 1581.1Sthorpej ldmia r0, {r0, r1} /* restore r0 and r1 */ 1591.1Sthorpej 1601.1Sthorpej /* OK, the machine state should be identical now to that when */ 1611.1Sthorpej /* OFW fielded the interrupt. So just fall through... */ 1621.1Sthorpej 1631.1Sthorpej sub lr, lr, #0x00000004 /* Adjust the lr */ 1641.1Sthorpej 1651.1Sthorpej PUSHFRAMEINSVC /* Push an interrupt frame */ 1661.1Sthorpej 1671.1Sthorpej /* 1681.11Smatt * Can't field this interrupt now if priority is IPL_CLOCK 1691.1Sthorpej * or higher. For now, we'll just ignore the interrupt. 1701.1Sthorpej * Soon, we will have to schedule it for later action. 1711.1Sthorpej */ 1721.1Sthorpej ldr r0, Lcurrent_spl_level 1731.11Smatt ldr r0, [r4, #CI_CPL] 1741.11Smatt cmp r0, #IPL_CLOCK 1751.1Sthorpej blt ofwtakeint 1761.1Sthorpej 1771.1Sthorpej PULLFRAMEFROMSVCANDEXIT 1781.1Sthorpej movs pc, lr /* Exit */ 1791.1Sthorpej 1801.1Sthorpej /* 1811.1Sthorpej * Stuff a bit-mask into r8 indicating which interrupts 1821.1Sthorpej * are pending. In our case, that is just the timer0 1831.1Sthorpej * interrupt: (1 << TIMER0). The existing code will take 1841.1Sthorpej * care of invoking that handler and the softint/ast stuff 1851.1Sthorpej * which follows it. 1861.1Sthorpej */ 1871.1Sthorpejofwtakeint: 1881.5Smanu#ifdef EXEC_AOUT 1891.3Sscw ldr r0, [sp] /* Fetch SPSR */ 1901.3Sscw#endif 1911.3Sscw ENABLE_ALIGNMENT_FAULTS 1921.3Sscw 1931.1Sthorpej mov r8, #0x00000001 /* timer interrupt pending! */ 1941.1Sthorpej mov r8, r8, lsl #IRQ_TIMER0 1951.1Sthorpej 1961.1Sthorpej /* 1971.1Sthorpej * Note that we have entered the IRQ handler. 1981.1Sthorpej * We are in SVC mode so we cannot use the processor mode 1991.1Sthorpej * to determine if we are in an IRQ. Instead we will count the 2001.1Sthorpej * each time the interrupt handler is nested. 2011.1Sthorpej */ 2021.1Sthorpej 2031.11Smatt ldr r1, [r4, #CI_INTR_DEPTH] 2041.1Sthorpej add r1, r1, #1 2051.11Smatt str r1, [r4, #CI_INTR_DEPTH] 2061.1Sthorpej 2071.1Sthorpej /* Block the current requested interrupts */ 2081.1Sthorpej ldr r1, Ldisabled_mask 2091.1Sthorpej ldr r0, [r1] 2101.1Sthorpej stmfd sp!, {r0} 2111.1Sthorpej orr r0, r0, r8 2121.1Sthorpej 2131.1Sthorpej /* 2141.1Sthorpej * Need to block all interrupts at the IPL or lower for 2151.1Sthorpej * all asserted interrupts. 2161.1Sthorpej * This basically emulates hardware interrupt priority levels. 2171.1Sthorpej * Means we need to go through the interrupt mask and for 2181.1Sthorpej * every asserted interrupt we need to mask out all other 2191.1Sthorpej * interrupts at the same or lower IPL. 2201.1Sthorpej * If only we could wait until the main loop but we need to sort 2211.1Sthorpej * this out first so interrupts can be re-enabled. 2221.1Sthorpej * 2231.1Sthorpej * This would benefit from a special ffs type routine 2241.1Sthorpej */ 2251.1Sthorpej 2261.11Smatt mov r9, #(NIPL - 1) 2271.13Smatt ldr r5, Lspl_masks 2281.1Sthorpej 2291.1SthorpejLfind_highest_ipl: 2301.13Smatt ldr r2, [r5, r9, lsl #2] 2311.1Sthorpej tst r8, r2 2321.1Sthorpej subeq r9, r9, #1 2331.1Sthorpej beq Lfind_highest_ipl 2341.1Sthorpej 2351.1Sthorpej /* r9 = SPL level of highest priority interrupt */ 2361.1Sthorpej add r9, r9, #1 2371.13Smatt ldr r2, [r5, r9, lsl #2] 2381.1Sthorpej mvn r2, r2 2391.1Sthorpej orr r0, r0, r2 2401.1Sthorpej 2411.1Sthorpej str r0, [r1] 2421.1Sthorpej 2431.1Sthorpej ldr r0, Lcurrent_spl_level 2441.11Smatt ldr r1, [r4, #CI_CPL] 2451.11Smatt str r9, [r4, #CI_CPL] 2461.1Sthorpej stmfd sp!, {r1} 2471.1Sthorpej 2481.1Sthorpej /* Update the irq masks */ 2491.1Sthorpej bl _C_LABEL(irq_setmasks) 2501.1Sthorpej 2511.6Smatt mrs r0, cpsr_all /* Enable IRQ's */ 2521.1Sthorpej bic r0, r0, #I32_bit 2531.1Sthorpej msr cpsr_all, r0 2541.1Sthorpej 2551.13Smatt ldr r5, Lirqhandlers 2561.6Smatt mov r9, #0x00000001 2571.1Sthorpej 2581.1Sthorpejirqloop: 2591.1Sthorpej /* This would benefit from a special ffs type routine */ 2601.1Sthorpej tst r8, r9 /* Is a bit set ? */ 2611.1Sthorpej beq nextirq /* No ? try next bit */ 2621.1Sthorpej 2631.13Smatt ldr r6, [r5] /* Get address of first handler structure */ 2641.1Sthorpej 2651.1Sthorpej teq r6, #0x00000000 /* Do we have a handler */ 2661.1Sthorpej moveq r0, r8 /* IRQ requests as arg 0 */ 2671.1Sthorpej beq _C_LABEL(stray_irqhandler) /* call special handler */ 2681.1Sthorpej 2691.12Smatt ldr r1, [r4, #(CI_CC_NINTR)] 2701.12Smatt ldr r2, [r4, #(CI_CC_NINTR+4)] 2711.12Smatt#ifdef _ARMEL 2721.12Smatt adds r1, r1, #0x00000001 2731.12Smatt adc r2, r2, #0x00000000 2741.12Smatt#else 2751.12Smatt adds r2, r2, #0x00000001 2761.12Smatt adc r1, r1, #0x00000000 2771.12Smatt#endif 2781.12Smatt str r1, [r4, #(CI_CC_NINTR)] 2791.12Smatt str r2, [r4, #(CI_CC_NINTR+4)] 2801.1Sthorpej 2811.1Sthorpejirqchainloop: 2821.1Sthorpej ldr r0, [r6, #(IH_ARG)] /* Get argument pointer */ 2831.1Sthorpej teq r0, #0x00000000 /* If arg is zero pass stack frame */ 2841.1Sthorpej addeq r0, sp, #8 /* ... stack frame */ 2851.2Sbjh21 mov lr, pc /* return address */ 2861.1Sthorpej ldr pc, [r6, #(IH_FUNC)] /* Call handler */ 2871.1Sthorpej 2881.1Sthorpej teq r0, #0x00000001 /* Was the irq serviced ? */ 2891.1Sthorpej beq irqdone 2901.1Sthorpej 2911.1Sthorpej ldr r6, [r6, #(IH_NEXT)] 2921.1Sthorpej teq r6, #0x00000000 2931.1Sthorpej bne irqchainloop 2941.6Smatt b nextirq 2951.1Sthorpej 2961.1Sthorpejirqdone: 2971.6Smatt add r3, r6, #IH_EV_COUNT /* get address of ih's ev_count */ 2981.6Smatt ldmia r3, {r1-r2} /* load ev_count */ 2991.6Smatt adds r1, r1, #0x00000001 /* 64bit incr (lo) */ 3001.6Smatt adc r2, r2, #0x00000000 /* 64bit incr (hi) */ 3011.6Smatt stmia r3, {r1-r2} /* store ev_count */ 3021.6Smatt 3031.1Sthorpejnextirq: 3041.13Smatt add r5, r5, #0x00000004 /* update pointer to handlers */ 3051.1Sthorpej mov r9, r9, lsl #1 /* move on to next bit */ 3061.1Sthorpej teq r9, #(1 << 24) /* done the last bit ? */ 3071.1Sthorpej bne irqloop /* no - loop back. */ 3081.1Sthorpej 3091.1Sthorpej ldmfd sp!, {r2} 3101.11Smatt str r2, [r4, #CI_CPL] 3111.1Sthorpej 3121.1Sthorpej /* Restore previous disabled mask */ 3131.1Sthorpej ldmfd sp!, {r2} 3141.1Sthorpej ldr r1, Ldisabled_mask 3151.1Sthorpej str r2, [r1] 3161.1Sthorpej bl _C_LABEL(irq_setmasks) 3171.1Sthorpej 3181.1Sthorpej bl _C_LABEL(dosoftints) /* Handle the soft interrupts */ 3191.1Sthorpej 3201.1Sthorpej /* Kill IRQ's in preparation for exit */ 3211.6Smatt mrs r0, cpsr_all 3221.6Smatt orr r0, r0, #(I32_bit) 3231.6Smatt msr cpsr_all, r0 3241.1Sthorpej 3251.1Sthorpej /* Decrement the nest count */ 3261.11Smatt ldr r1, [r4, #CI_INTR_DEPTH] 3271.1Sthorpej sub r1, r1, #1 3281.11Smatt str r1, [r4, #CI_INTR_DEPTH] 3291.1Sthorpej 3301.7Sthorpej LOCK_CAS_CHECK 3311.7Sthorpej 3321.3Sscw DO_AST_AND_RESTORE_ALIGNMENT_FAULTS 3331.1Sthorpej PULLFRAMEFROMSVCANDEXIT 3341.1Sthorpej movs pc, lr /* Exit */ 3351.1Sthorpej 3361.1SthorpejLcurrent_mask: 3371.1Sthorpej .word _C_LABEL(current_mask) /* irq's that are usable */ 3381.1Sthorpej 3391.1Sthorpej 3401.1SthorpejENTRY(irq_setmasks) 3411.1Sthorpej /* Do nothing */ 3421.1Sthorpej mov pc, lr 3431.1Sthorpej 3441.1Sthorpej 3451.1SthorpejLirqhandlers: 3461.1Sthorpej .word _C_LABEL(irqhandlers) /* Pointer to array of irqhandlers */ 3471.1Sthorpej 3481.1Sthorpej .text 3491.1Sthorpej .global _C_LABEL(dotickgrovelling) 3501.1Sthorpej 3511.1Sthorpej/* 3521.1Sthorpej * Do magic to cause OFW to call our irq_entry 3531.1Sthorpej * routine when it returns from its tick-handling. 3541.1Sthorpej * 3551.1Sthorpej * This consists of two sub-tasks: 3561.1Sthorpej * - save some machine state in ofw_ticktmp 3571.1Sthorpej * - punch some new machine state into the 3581.1Sthorpej * OFW-supplied frame 3591.1Sthorpej * 3601.1Sthorpej * We are running in the IRQ frame, with 3611.1Sthorpej * interrupts disabled. 3621.1Sthorpej * 3631.1Sthorpej * r0 - base of saved OFW interrupt frame, which 3641.1Sthorpej * has the following format: 3651.1Sthorpej * 3661.1Sthorpej * pc // interrupted instruction 3671.1Sthorpej * lr // lr of interrupted context 3681.1Sthorpej * sp // sp of interrupted context 3691.1Sthorpej * r12 3701.1Sthorpej * ... // non-banked register values 3711.1Sthorpej * ... // of interrupted context 3721.1Sthorpej * r0 3731.1Sthorpej * spsr // psr of interrupted context 3741.1Sthorpej * 3751.1Sthorpej */ 3761.1Sthorpej 3771.1Sthorpej_C_LABEL(dotickgrovelling): 3781.1Sthorpej /*assert((cpsr & PSR_MODE) == PSR_IRQ32_MODE);*/ 3791.1Sthorpej 3801.1Sthorpej stmfd sp!, {r1-r5} /* scratch registers r1-r5 */ 3811.1Sthorpej 3821.1Sthorpej /* 3831.1Sthorpej * Sub-task 1: 3841.1Sthorpej * 3851.1Sthorpej * Our irq_entry routine needs to re-construct 3861.1Sthorpej * the state of the machine at the time OFW 3871.1Sthorpej * fielded the interrupt, so that we can use 3881.1Sthorpej * the rest of the standard interrupt-handling 3891.1Sthorpej * code. Specifically, irq_entry needs to get 3901.1Sthorpej * at the following machine state: 3911.1Sthorpej * 3921.1Sthorpej * pc // interrupted instruction 3931.1Sthorpej * lr_usr 3941.1Sthorpej * sp_usr 3951.1Sthorpej * r0-r12 // the non-banked registers 3961.1Sthorpej * // at the time of interruption 3971.1Sthorpej * spsr // cpsr of interrupted context 3981.1Sthorpej * 3991.1Sthorpej * The non-banked registers will be valid at the 4001.1Sthorpej * time irq_entry is called, but the other values 4011.1Sthorpej * will not be. We must save them here, in the 4021.1Sthorpej * ofw_ticktmp storage block. We also save r0 4031.1Sthorpej * and r1 so that we have some free registers 4041.1Sthorpej * when it's time to do the re-construction. 4051.1Sthorpej * 4061.1Sthorpej * Note that interrupts are not enabled before 4071.1Sthorpej * irq_entry is entered, so we don't have to 4081.1Sthorpej * worry about ofw_ticktmp getting clobbered. 4091.1Sthorpej */ 4101.1Sthorpej ldr r1, Lofw_ticktmp /* r1 points to ofw_ticktmp[0] */ 4111.1Sthorpej 4121.1Sthorpej ldr r2, [r0, #0] /* ofwframe[0] is spsr */ 4131.1Sthorpej stmia r1!, {r2} /* put it in ofw_ticktmp[0] */ 4141.1Sthorpej 4151.1Sthorpej ldr r2, [r0, #(4*1)] /* ofwframe[1] is saved r0 */ 4161.1Sthorpej stmia r1!, {r2} /* put it in ofw_ticktmp[1] */ 4171.1Sthorpej 4181.1Sthorpej ldr r2, [r0, #(4*2)] /* ofwframe[2] is saved r1 */ 4191.1Sthorpej stmia r1!, {r2} /* put it in ofw_ticktmp[2] */ 4201.1Sthorpej 4211.1Sthorpej stmia r1, {sp, lr}^ /* put {sp,lr}_usr in ofw_ticktmp[3,4]; */ 4221.1Sthorpej /* the user registers are still valid */ 4231.1Sthorpej /* because we haven't left IRQ mode */ 4241.1Sthorpej add r1, r1, #(4*2) /* previous instruction can't writeback */ 4251.1Sthorpej /* this one can't use banked registers */ 4261.1Sthorpej 4271.1Sthorpej ldr r2, [r0, #(4*16)] /* ofwframe[16] is pc */ 4281.1Sthorpej stmia r1!, {r2} /* put it in ofw_ticktmp[5] */ 4291.1Sthorpej 4301.1Sthorpej 4311.1Sthorpej /* 4321.1Sthorpej * Sub-task 2: 4331.1Sthorpej * 4341.1Sthorpej * Diddle the OFW-supplied frame such that 4351.1Sthorpej * control passes to irq_entry when OFW does 4361.1Sthorpej * its return from interrupt. There are 4 4371.1Sthorpej * fields in that frame that we need to plug: 4381.1Sthorpej * 4391.1Sthorpej * pc // gets irq_entry 4401.1Sthorpej * lr // gets lr_svc 4411.1Sthorpej * sp // gets sp_svc 4421.1Sthorpej * spsr // gets (I32_bit | PSR_SVC32_MODE) 4431.1Sthorpej * 4441.1Sthorpej */ 4451.1Sthorpej mov r1, #(I32_bit | PSR_SVC32_MODE) 4461.1Sthorpej str r1, [r0, #0] /* plug spsr */ 4471.1Sthorpej 4481.1Sthorpej /* Sneak into SVC mode to get sp and lr */ 4491.1Sthorpej mrs r3, cpsr_all 4501.1Sthorpej bic r3, r3, #(PSR_MODE) 4511.1Sthorpej orr r3, r3, #(PSR_SVC32_MODE) 4521.1Sthorpej msr cpsr_all, r3 4531.1Sthorpej mov r4, lr /* snarf lr_svc */ 4541.1Sthorpej mov r5, sp /* snarf sp_svc */ 4551.1Sthorpej bic r3, r3, #(PSR_MODE) 4561.1Sthorpej orr r3, r3, #(PSR_IRQ32_MODE) 4571.1Sthorpej msr cpsr_all, r3 4581.1Sthorpej str r5, [r0, #(4*14)] /* plug sp */ 4591.1Sthorpej str r4, [r0, #(4*15)] /* plug lr */ 4601.1Sthorpej 4611.2Sbjh21 ldr r1, Lirq_entry 4621.1Sthorpej str r1, [r0, #(4*16)] /* plug pc */ 4631.1Sthorpej 4641.1Sthorpej ldmfd sp!, {r1-r5} 4651.1Sthorpej mov pc, lr 4661.1Sthorpej 4671.1Sthorpej 4681.1Sthorpej .bss 4691.1Sthorpej .align 0 4701.1Sthorpej 4711.1Sthorpej_C_LABEL(ofw_ticktmp): 4721.1Sthorpej .space 4 * 6 /* temporary storage for 6 words of machine state */ 4731.1Sthorpej 4741.1Sthorpejofwirqstk: /* hack */ 4751.1Sthorpej .space 4096 476