ofw_irq.S revision 1.7
11.7Sthorpej/* $NetBSD: ofw_irq.S,v 1.7 2007/03/09 19:21:59 thorpej 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.1Sthorpej#include <machine/asm.h> 441.1Sthorpej#include <machine/cpu.h> 451.1Sthorpej#include <machine/frame.h> 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.1SthorpejLcurrent_spl_level: 791.1Sthorpej .word _C_LABEL(current_spl_level) 801.1Sthorpej 811.1SthorpejLcurrent_intr_depth: 821.1Sthorpej .word _C_LABEL(current_intr_depth) 831.1Sthorpej 841.1SthorpejLspl_masks: 851.1Sthorpej .word _C_LABEL(spl_masks) 861.1Sthorpej 871.1SthorpejLofw_ticktmp: 881.1Sthorpej .word _C_LABEL(ofw_ticktmp) 891.1Sthorpej 901.1SthorpejLirq_entry: 911.1Sthorpej .word irq_entry 921.1Sthorpej 931.1SthorpejLofwirqstk: /* hack */ 941.1Sthorpej .word ofwirqstk + 4096 951.1Sthorpej 961.7SthorpejLOCK_CAS_CHECK_LOCALS 971.7Sthorpej 981.3SscwAST_ALIGNMENT_FAULT_LOCALS 991.3Sscw 1001.1Sthorpej/* 1011.1Sthorpej * Regsister usage 1021.1Sthorpej * 1031.1Sthorpej * r6 - Address of current handler 1041.1Sthorpej * r7 - Pointer to handler pointer list 1051.1Sthorpej * r8 - Current IRQ requests. 1061.1Sthorpej * r9 - Used to count through possible IRQ bits. 1071.1Sthorpej * r10 - Base address of IOMD 1081.1Sthorpej */ 1091.1Sthorpej 1101.1SthorpejASENTRY_NP(irq_entry) 1111.1Sthorpej /* 1121.1Sthorpej * We come here following an OFW-handled timer tick. 1131.1Sthorpej * 1141.1Sthorpej * We are in the SVC frame, and interrupts are disabled. 1151.1Sthorpej * The state of the interrupted context is partially in 1161.1Sthorpej * the registers and partially in the global storage area 1171.1Sthorpej * labeled ofw_ticktmp. ofw_ticktmp is filled-in by the 1181.1Sthorpej * tick callback that is invoked by OFW on the way out of 1191.1Sthorpej * its interrupt handler. ofw_ticktmp contains the following: 1201.1Sthorpej * 1211.1Sthorpej * pc // interrupted instruction 1221.1Sthorpej * lr_usr 1231.1Sthorpej * sp_usr 1241.1Sthorpej * r1 // makes r1 available for scratch 1251.1Sthorpej * r0 // makes r0 available for scratch 1261.1Sthorpej * spsr_svc // cpsr of interrupted context 1271.1Sthorpej * 1281.1Sthorpej * The prologue of this routine must re-construct the 1291.1Sthorpej * machine state that existed at the time OFW's interrupt- 1301.1Sthorpej * handler fielded the interrupt. That allows us to use 1311.1Sthorpej * the rest of the code in this routine, and have it all 1321.1Sthorpej * "just work." 1331.1Sthorpej */ 1341.1Sthorpej 1351.1Sthorpej /* 1361.1Sthorpej * Switch to IRQ mode. 1371.1Sthorpej * First check the spsr in ofw_ticktmp to see what the FIQ bit should be. 1381.1Sthorpej * 1391.1Sthorpej * I need 2 scratch registers to do this. 1401.1Sthorpej * Fortunately, r0 and r1 are already saved in ofw_ticktmp. 1411.1Sthorpej * How convenient. 1421.1Sthorpej */ 1431.1Sthorpej ldr r0, Lofw_ticktmp 1441.1Sthorpej ldr r0, [r0] 1451.1Sthorpej and r0, r0, #F32_bit 1461.1Sthorpej mov r1, #(I32_bit | PSR_IRQ32_MODE) 1471.1Sthorpej orr r1, r1, r0 1481.1Sthorpej msr cpsr_all, r1 1491.1Sthorpej 1501.1Sthorpej /* Now we're in IRQ mode. */ 1511.1Sthorpej /* Restore contents of ofw_ticktmp. */ 1521.2Sbjh21 adr r0, Lofwirqstk /* Bummer! Mitch hasn't left me a stack. */ 1531.2Sbjh21 ldr sp, [r0] /* I'll use my own for now... */ 1541.1Sthorpej ldr r0, Lofw_ticktmp /* r0 now points to ofw_ticktmp[0] */ 1551.1Sthorpej ldr r1, [r0], #(4*3) /* skip over saved {r0, r1} */ 1561.1Sthorpej msr spsr_all, r1 /* restore spsr */ 1571.1Sthorpej ldmia r0, {sp, lr}^ /* restore user sp and lr */ 1581.1Sthorpej add r0, r0, #(4*2) /* previous instruction can't writeback */ 1591.1Sthorpej /* this one can't use banked registers */ 1601.1Sthorpej ldr lr, [r0], #(-4*4) /* restore pc; point r0 at ofw_ticktmp[1] */ 1611.1Sthorpej add lr, lr, #4 /* pc += 4; will be decremented below */ 1621.1Sthorpej ldmia r0, {r0, r1} /* restore r0 and r1 */ 1631.1Sthorpej 1641.1Sthorpej /* OK, the machine state should be identical now to that when */ 1651.1Sthorpej /* OFW fielded the interrupt. So just fall through... */ 1661.1Sthorpej 1671.1Sthorpej sub lr, lr, #0x00000004 /* Adjust the lr */ 1681.1Sthorpej 1691.1Sthorpej PUSHFRAMEINSVC /* Push an interrupt frame */ 1701.1Sthorpej 1711.1Sthorpej /* 1721.1Sthorpej * Can't field this interrupt now if priority is _SPL_CLOCK 1731.1Sthorpej * or higher. For now, we'll just ignore the interrupt. 1741.1Sthorpej * Soon, we will have to schedule it for later action. 1751.1Sthorpej */ 1761.1Sthorpej ldr r0, Lcurrent_spl_level 1771.1Sthorpej ldr r0, [r0] 1781.1Sthorpej cmp r0, #_SPL_CLOCK 1791.1Sthorpej blt ofwtakeint 1801.1Sthorpej 1811.1Sthorpej PULLFRAMEFROMSVCANDEXIT 1821.1Sthorpej movs pc, lr /* Exit */ 1831.1Sthorpej 1841.1Sthorpej /* 1851.1Sthorpej * Stuff a bit-mask into r8 indicating which interrupts 1861.1Sthorpej * are pending. In our case, that is just the timer0 1871.1Sthorpej * interrupt: (1 << TIMER0). The existing code will take 1881.1Sthorpej * care of invoking that handler and the softint/ast stuff 1891.1Sthorpej * which follows it. 1901.1Sthorpej */ 1911.1Sthorpejofwtakeint: 1921.5Smanu#ifdef EXEC_AOUT 1931.3Sscw ldr r0, [sp] /* Fetch SPSR */ 1941.3Sscw#endif 1951.3Sscw ENABLE_ALIGNMENT_FAULTS 1961.3Sscw 1971.1Sthorpej mov r8, #0x00000001 /* timer interrupt pending! */ 1981.1Sthorpej mov r8, r8, lsl #IRQ_TIMER0 1991.1Sthorpej 2001.1Sthorpej /* 2011.1Sthorpej * Note that we have entered the IRQ handler. 2021.1Sthorpej * We are in SVC mode so we cannot use the processor mode 2031.1Sthorpej * to determine if we are in an IRQ. Instead we will count the 2041.1Sthorpej * each time the interrupt handler is nested. 2051.1Sthorpej */ 2061.1Sthorpej 2071.1Sthorpej ldr r0, Lcurrent_intr_depth 2081.1Sthorpej ldr r1, [r0] 2091.1Sthorpej add r1, r1, #1 2101.1Sthorpej str r1, [r0] 2111.1Sthorpej 2121.1Sthorpej /* Block the current requested interrupts */ 2131.1Sthorpej ldr r1, Ldisabled_mask 2141.1Sthorpej ldr r0, [r1] 2151.1Sthorpej stmfd sp!, {r0} 2161.1Sthorpej orr r0, r0, r8 2171.1Sthorpej 2181.1Sthorpej /* 2191.1Sthorpej * Need to block all interrupts at the IPL or lower for 2201.1Sthorpej * all asserted interrupts. 2211.1Sthorpej * This basically emulates hardware interrupt priority levels. 2221.1Sthorpej * Means we need to go through the interrupt mask and for 2231.1Sthorpej * every asserted interrupt we need to mask out all other 2241.1Sthorpej * interrupts at the same or lower IPL. 2251.1Sthorpej * If only we could wait until the main loop but we need to sort 2261.1Sthorpej * this out first so interrupts can be re-enabled. 2271.1Sthorpej * 2281.1Sthorpej * This would benefit from a special ffs type routine 2291.1Sthorpej */ 2301.1Sthorpej 2311.1Sthorpej mov r9, #(_SPL_LEVELS - 1) 2321.1Sthorpej ldr r7, Lspl_masks 2331.1Sthorpej 2341.1SthorpejLfind_highest_ipl: 2351.1Sthorpej ldr r2, [r7, r9, lsl #2] 2361.1Sthorpej tst r8, r2 2371.1Sthorpej subeq r9, r9, #1 2381.1Sthorpej beq Lfind_highest_ipl 2391.1Sthorpej 2401.1Sthorpej /* r9 = SPL level of highest priority interrupt */ 2411.1Sthorpej add r9, r9, #1 2421.1Sthorpej ldr r2, [r7, r9, lsl #2] 2431.1Sthorpej mvn r2, r2 2441.1Sthorpej orr r0, r0, r2 2451.1Sthorpej 2461.1Sthorpej str r0, [r1] 2471.1Sthorpej 2481.1Sthorpej ldr r0, Lcurrent_spl_level 2491.1Sthorpej ldr r1, [r0] 2501.1Sthorpej str r9, [r0] 2511.1Sthorpej stmfd sp!, {r1} 2521.1Sthorpej 2531.1Sthorpej /* Update the irq masks */ 2541.1Sthorpej bl _C_LABEL(irq_setmasks) 2551.1Sthorpej 2561.6Smatt mrs r0, cpsr_all /* Enable IRQ's */ 2571.1Sthorpej bic r0, r0, #I32_bit 2581.1Sthorpej msr cpsr_all, r0 2591.1Sthorpej 2601.2Sbjh21 ldr r7, Lirqhandlers 2611.6Smatt mov r9, #0x00000001 2621.1Sthorpej 2631.1Sthorpejirqloop: 2641.1Sthorpej /* This would benefit from a special ffs type routine */ 2651.1Sthorpej tst r8, r9 /* Is a bit set ? */ 2661.1Sthorpej beq nextirq /* No ? try next bit */ 2671.1Sthorpej 2681.1Sthorpej ldr r6, [r7] /* Get address of first handler structure */ 2691.1Sthorpej 2701.1Sthorpej teq r6, #0x00000000 /* Do we have a handler */ 2711.1Sthorpej moveq r0, r8 /* IRQ requests as arg 0 */ 2721.1Sthorpej beq _C_LABEL(stray_irqhandler) /* call special handler */ 2731.1Sthorpej 2741.6Smatt ldr r0, Lcnt 2751.1Sthorpej ldr r1, [r0, #(V_INTR)] 2761.1Sthorpej add r1, r1, #0x00000001 2771.1Sthorpej str r1, [r0, #(V_INTR)] 2781.1Sthorpej 2791.1Sthorpejirqchainloop: 2801.1Sthorpej ldr r0, [r6, #(IH_ARG)] /* Get argument pointer */ 2811.1Sthorpej teq r0, #0x00000000 /* If arg is zero pass stack frame */ 2821.1Sthorpej addeq r0, sp, #8 /* ... stack frame */ 2831.2Sbjh21 mov lr, pc /* return address */ 2841.1Sthorpej ldr pc, [r6, #(IH_FUNC)] /* Call handler */ 2851.1Sthorpej 2861.1Sthorpej teq r0, #0x00000001 /* Was the irq serviced ? */ 2871.1Sthorpej beq irqdone 2881.1Sthorpej 2891.1Sthorpej ldr r6, [r6, #(IH_NEXT)] 2901.1Sthorpej teq r6, #0x00000000 2911.1Sthorpej bne irqchainloop 2921.6Smatt b nextirq 2931.1Sthorpej 2941.1Sthorpejirqdone: 2951.6Smatt add r3, r6, #IH_EV_COUNT /* get address of ih's ev_count */ 2961.6Smatt ldmia r3, {r1-r2} /* load ev_count */ 2971.6Smatt adds r1, r1, #0x00000001 /* 64bit incr (lo) */ 2981.6Smatt adc r2, r2, #0x00000000 /* 64bit incr (hi) */ 2991.6Smatt stmia r3, {r1-r2} /* store ev_count */ 3001.6Smatt 3011.1Sthorpejnextirq: 3021.1Sthorpej add r7, r7, #0x00000004 /* update pointer to handlers */ 3031.1Sthorpej mov r9, r9, lsl #1 /* move on to next bit */ 3041.1Sthorpej teq r9, #(1 << 24) /* done the last bit ? */ 3051.1Sthorpej bne irqloop /* no - loop back. */ 3061.1Sthorpej 3071.1Sthorpej ldmfd sp!, {r2} 3081.1Sthorpej ldr r1, Lcurrent_spl_level 3091.1Sthorpej str r2, [r1] 3101.1Sthorpej 3111.1Sthorpej /* Restore previous disabled mask */ 3121.1Sthorpej ldmfd sp!, {r2} 3131.1Sthorpej ldr r1, Ldisabled_mask 3141.1Sthorpej str r2, [r1] 3151.1Sthorpej bl _C_LABEL(irq_setmasks) 3161.1Sthorpej 3171.1Sthorpej bl _C_LABEL(dosoftints) /* Handle the soft interrupts */ 3181.1Sthorpej 3191.1Sthorpej /* Kill IRQ's in preparation for exit */ 3201.6Smatt mrs r0, cpsr_all 3211.6Smatt orr r0, r0, #(I32_bit) 3221.6Smatt msr cpsr_all, r0 3231.1Sthorpej 3241.1Sthorpej /* Decrement the nest count */ 3251.1Sthorpej ldr r0, Lcurrent_intr_depth 3261.1Sthorpej ldr r1, [r0] 3271.1Sthorpej sub r1, r1, #1 3281.1Sthorpej str r1, [r0] 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.1SthorpejLspl_mask: 3371.1Sthorpej .word _C_LABEL(spl_mask) /* irq's allowed at current spl level */ 3381.1Sthorpej 3391.1SthorpejLcurrent_mask: 3401.1Sthorpej .word _C_LABEL(current_mask) /* irq's that are usable */ 3411.1Sthorpej 3421.1Sthorpej 3431.1SthorpejENTRY(irq_setmasks) 3441.1Sthorpej /* Do nothing */ 3451.1Sthorpej mov pc, lr 3461.1Sthorpej 3471.1Sthorpej 3481.1SthorpejLcnt: 3491.1Sthorpej .word _C_LABEL(uvmexp) 3501.1Sthorpej 3511.1SthorpejLirqhandlers: 3521.1Sthorpej .word _C_LABEL(irqhandlers) /* Pointer to array of irqhandlers */ 3531.1Sthorpej 3541.1Sthorpej .text 3551.1Sthorpej .global _C_LABEL(dotickgrovelling) 3561.1Sthorpej 3571.1Sthorpej/* 3581.1Sthorpej * Do magic to cause OFW to call our irq_entry 3591.1Sthorpej * routine when it returns from its tick-handling. 3601.1Sthorpej * 3611.1Sthorpej * This consists of two sub-tasks: 3621.1Sthorpej * - save some machine state in ofw_ticktmp 3631.1Sthorpej * - punch some new machine state into the 3641.1Sthorpej * OFW-supplied frame 3651.1Sthorpej * 3661.1Sthorpej * We are running in the IRQ frame, with 3671.1Sthorpej * interrupts disabled. 3681.1Sthorpej * 3691.1Sthorpej * r0 - base of saved OFW interrupt frame, which 3701.1Sthorpej * has the following format: 3711.1Sthorpej * 3721.1Sthorpej * pc // interrupted instruction 3731.1Sthorpej * lr // lr of interrupted context 3741.1Sthorpej * sp // sp of interrupted context 3751.1Sthorpej * r12 3761.1Sthorpej * ... // non-banked register values 3771.1Sthorpej * ... // of interrupted context 3781.1Sthorpej * r0 3791.1Sthorpej * spsr // psr of interrupted context 3801.1Sthorpej * 3811.1Sthorpej */ 3821.1Sthorpej 3831.1Sthorpej_C_LABEL(dotickgrovelling): 3841.1Sthorpej /*assert((cpsr & PSR_MODE) == PSR_IRQ32_MODE);*/ 3851.1Sthorpej 3861.1Sthorpej stmfd sp!, {r1-r5} /* scratch registers r1-r5 */ 3871.1Sthorpej 3881.1Sthorpej /* 3891.1Sthorpej * Sub-task 1: 3901.1Sthorpej * 3911.1Sthorpej * Our irq_entry routine needs to re-construct 3921.1Sthorpej * the state of the machine at the time OFW 3931.1Sthorpej * fielded the interrupt, so that we can use 3941.1Sthorpej * the rest of the standard interrupt-handling 3951.1Sthorpej * code. Specifically, irq_entry needs to get 3961.1Sthorpej * at the following machine state: 3971.1Sthorpej * 3981.1Sthorpej * pc // interrupted instruction 3991.1Sthorpej * lr_usr 4001.1Sthorpej * sp_usr 4011.1Sthorpej * r0-r12 // the non-banked registers 4021.1Sthorpej * // at the time of interruption 4031.1Sthorpej * spsr // cpsr of interrupted context 4041.1Sthorpej * 4051.1Sthorpej * The non-banked registers will be valid at the 4061.1Sthorpej * time irq_entry is called, but the other values 4071.1Sthorpej * will not be. We must save them here, in the 4081.1Sthorpej * ofw_ticktmp storage block. We also save r0 4091.1Sthorpej * and r1 so that we have some free registers 4101.1Sthorpej * when it's time to do the re-construction. 4111.1Sthorpej * 4121.1Sthorpej * Note that interrupts are not enabled before 4131.1Sthorpej * irq_entry is entered, so we don't have to 4141.1Sthorpej * worry about ofw_ticktmp getting clobbered. 4151.1Sthorpej */ 4161.1Sthorpej ldr r1, Lofw_ticktmp /* r1 points to ofw_ticktmp[0] */ 4171.1Sthorpej 4181.1Sthorpej ldr r2, [r0, #0] /* ofwframe[0] is spsr */ 4191.1Sthorpej stmia r1!, {r2} /* put it in ofw_ticktmp[0] */ 4201.1Sthorpej 4211.1Sthorpej ldr r2, [r0, #(4*1)] /* ofwframe[1] is saved r0 */ 4221.1Sthorpej stmia r1!, {r2} /* put it in ofw_ticktmp[1] */ 4231.1Sthorpej 4241.1Sthorpej ldr r2, [r0, #(4*2)] /* ofwframe[2] is saved r1 */ 4251.1Sthorpej stmia r1!, {r2} /* put it in ofw_ticktmp[2] */ 4261.1Sthorpej 4271.1Sthorpej stmia r1, {sp, lr}^ /* put {sp,lr}_usr in ofw_ticktmp[3,4]; */ 4281.1Sthorpej /* the user registers are still valid */ 4291.1Sthorpej /* because we haven't left IRQ mode */ 4301.1Sthorpej add r1, r1, #(4*2) /* previous instruction can't writeback */ 4311.1Sthorpej /* this one can't use banked registers */ 4321.1Sthorpej 4331.1Sthorpej ldr r2, [r0, #(4*16)] /* ofwframe[16] is pc */ 4341.1Sthorpej stmia r1!, {r2} /* put it in ofw_ticktmp[5] */ 4351.1Sthorpej 4361.1Sthorpej 4371.1Sthorpej /* 4381.1Sthorpej * Sub-task 2: 4391.1Sthorpej * 4401.1Sthorpej * Diddle the OFW-supplied frame such that 4411.1Sthorpej * control passes to irq_entry when OFW does 4421.1Sthorpej * its return from interrupt. There are 4 4431.1Sthorpej * fields in that frame that we need to plug: 4441.1Sthorpej * 4451.1Sthorpej * pc // gets irq_entry 4461.1Sthorpej * lr // gets lr_svc 4471.1Sthorpej * sp // gets sp_svc 4481.1Sthorpej * spsr // gets (I32_bit | PSR_SVC32_MODE) 4491.1Sthorpej * 4501.1Sthorpej */ 4511.1Sthorpej mov r1, #(I32_bit | PSR_SVC32_MODE) 4521.1Sthorpej str r1, [r0, #0] /* plug spsr */ 4531.1Sthorpej 4541.1Sthorpej /* Sneak into SVC mode to get sp and lr */ 4551.1Sthorpej mrs r3, cpsr_all 4561.1Sthorpej bic r3, r3, #(PSR_MODE) 4571.1Sthorpej orr r3, r3, #(PSR_SVC32_MODE) 4581.1Sthorpej msr cpsr_all, r3 4591.1Sthorpej mov r4, lr /* snarf lr_svc */ 4601.1Sthorpej mov r5, sp /* snarf sp_svc */ 4611.1Sthorpej bic r3, r3, #(PSR_MODE) 4621.1Sthorpej orr r3, r3, #(PSR_IRQ32_MODE) 4631.1Sthorpej msr cpsr_all, r3 4641.1Sthorpej str r5, [r0, #(4*14)] /* plug sp */ 4651.1Sthorpej str r4, [r0, #(4*15)] /* plug lr */ 4661.1Sthorpej 4671.2Sbjh21 ldr r1, Lirq_entry 4681.1Sthorpej str r1, [r0, #(4*16)] /* plug pc */ 4691.1Sthorpej 4701.1Sthorpej ldmfd sp!, {r1-r5} 4711.1Sthorpej mov pc, lr 4721.1Sthorpej 4731.1Sthorpej 4741.1Sthorpej .bss 4751.1Sthorpej .align 0 4761.1Sthorpej 4771.1Sthorpej_C_LABEL(ofw_ticktmp): 4781.1Sthorpej .space 4 * 6 /* temporary storage for 6 words of machine state */ 4791.1Sthorpej 4801.1Sthorpejofwirqstk: /* hack */ 4811.1Sthorpej .space 4096 482