📄 cpu_asm.s
字号:
/* * TODO: * Context_switch needs to only save callee save registers * I think this means can skip: r1, r2, r19-29, r31 * Ref: p 3-2 of Procedure Calling Conventions Manual * This should be #ifndef DEBUG so that debugger has * accurate visibility into all registers * * This file contains the assembly code for the HPPA implementation * of RTEMS. * * COPYRIGHT (c) 1994,95 by Division Incorporated * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rtems.com/license/LICENSE. * * $Id: cpu_asm.S,v 1.3.2.1 2003/09/04 18:47:25 joel Exp $ */#include <rtems/score/hppa.h>#include <rtems/score/cpu_asm.h>#include <rtems/score/cpu.h>#include <rtems/score/offsets.h>#if 0#define TEXT_SEGMENT \ .SPACE $TEXT$ !\ .SUBSPA $CODE$#define RO_SEGMENT \ .SPACE $TEXT$ !\ .SUBSPA $lit$#define DATA_SEGMENT \ .SPACE $PRIVATE$ !\ .SUBSPA $data$#define BSS_SEGMENT \ .SPACE $PRIVATE$ !\ .SUBSPA $bss$#else#define TEXT_SEGMENT .text #define RO_SEGMENT .rodata #define DATA_SEGMENT .data#define BSS_SEGMENT .bss#endif #if 0 .SPACE $PRIVATE$ .SUBSPA $DATA$,QUAD=1,ALIGN=8,ACCESS=31 .SUBSPA $BSS$,QUAD=1,ALIGN=8,ACCESS=31,ZERO,SORT=82 .SPACE $TEXT$ .SUBSPA $LIT$,QUAD=0,ALIGN=8,ACCESS=44 .SUBSPA $CODE$,QUAD=0,ALIGN=8,ACCESS=44,CODE_ONLY .SPACE $TEXT$ .SUBSPA $CODE$#endif TEXT_SEGMENT/* * Special register usage for context switch and interrupts * Stay away from %cr28 which is used for TLB misses on 72000 */isr_arg0 .reg %cr24isr_r9 .reg %cr25isr_r8 .reg %cr26/* * Interrupt stack frame looks like this * * offset item * ----------------------------------------------------------------- * INTEGER_CONTEXT_OFFSET Context_Control * FP_CONTEXT_OFFSET Context_Control_fp * * It is padded out to a multiple of 64 *//*PAGE^L * void _Generic_ISR_Handler() * * This routine provides the RTEMS interrupt management. * * We jump here from the interrupt vector. * The HPPA hardware has done some stuff for us: * PSW saved in IPSW * PSW set to 0 * PSW[E] set to default (0) * PSW[M] set to 1 iff this is HPMC * * IIA queue is frozen (since PSW[Q] is now 0) * privilege level promoted to 0 * IIR, ISR, IOR potentially updated if PSW[Q] was 1 at trap * registers GR 1,8,9,16,17,24,25 copied to shadow regs * SHR 0 1 2 3 4 5 6 * * Our vector stub (in the BSP) MUST have done the following: * * a) Saved the original %r9 into %isr_r9 (%cr25) * b) Placed the vector number in %r9 * c) Was allowed to also destroy $isr_r8 (%cr26), * but the stub was NOT allowed to destroy any other registers. * * The typical stub sequence (in the BSP) should look like this: * * a) mtctl %r9,isr_r9 ; (save r9 in cr25) * b) ldi vector,%r9 ; (load constant vector number in r9) * c) mtctl %r8,isr_r8 ; (save r8 in cr26) * d) ldil L%MY_BSP_first_level_interrupt_handler,%r8 * e) ldo R%MY_BSP_first_level_interrupt_handler(%r8),%r8 * ; (point to BSP raw handler table) * f) ldwx,s %r9(%r8),%r8 ; (load value from raw handler table) * g) bv 0(%r8) ; (call raw handler: _Generic_ISR_Handler) * h) mfctl isr_r8,%r8 ; (restore r8 from cr26 in delay slot) * * Optionally, steps (c) thru (h) _could_ be replaced with a single * bl,n _Generic_ISR_Handler,%r0 * * */ .EXPORT _Generic_ISR_Handler,ENTRY,PRIV_LEV=0_Generic_ISR_Handler: .PROC .CALLINFO FRAME=0,NO_CALLS .ENTRY mtctl arg0, isr_arg0/* * save interrupt state */ mfctl ipsw, arg0 stw arg0, IPSW_OFFSET(sp) mfctl iir, arg0 stw arg0, IIR_OFFSET(sp) mfctl ior, arg0 stw arg0, IOR_OFFSET(sp) mfctl pcoq, arg0 stw arg0, PCOQFRONT_OFFSET(sp) mtctl %r0, pcoq mfctl pcoq, arg0 stw arg0, PCOQBACK_OFFSET(sp) mfctl %sar, arg0 stw arg0, SAR_OFFSET(sp)/* * Build an interrupt frame to hold the contexts we will need. * We have already saved the interrupt items on the stack * * At this point the following registers are damaged wrt the interrupt * reg current value saved value * ------------------------------------------------ * arg0 scratch isr_arg0 (cr24) * r9 vector number isr_r9 (cr25) * * Point to beginning of integer context and * save the integer context */ stw %r1,R1_OFFSET(sp) stw %r2,R2_OFFSET(sp) stw %r3,R3_OFFSET(sp) stw %r4,R4_OFFSET(sp) stw %r5,R5_OFFSET(sp) stw %r6,R6_OFFSET(sp) stw %r7,R7_OFFSET(sp) stw %r8,R8_OFFSET(sp)/* * skip r9 */ stw %r10,R10_OFFSET(sp) stw %r11,R11_OFFSET(sp) stw %r12,R12_OFFSET(sp) stw %r13,R13_OFFSET(sp) stw %r14,R14_OFFSET(sp) stw %r15,R15_OFFSET(sp) stw %r16,R16_OFFSET(sp) stw %r17,R17_OFFSET(sp) stw %r18,R18_OFFSET(sp) stw %r19,R19_OFFSET(sp) stw %r20,R20_OFFSET(sp) stw %r21,R21_OFFSET(sp) stw %r22,R22_OFFSET(sp) stw %r23,R23_OFFSET(sp) stw %r24,R24_OFFSET(sp) stw %r25,R25_OFFSET(sp)/* * skip arg0 */ stw %r27,R27_OFFSET(sp) stw %r28,R28_OFFSET(sp) stw %r29,R29_OFFSET(sp) stw %r30,R30_OFFSET(sp) stw %r31,R31_OFFSET(sp)/* Now most registers are available since they have been saved * * The following items are currently wrong in the integer context * reg current value saved value * ------------------------------------------------ * arg0 scratch isr_arg0 (cr24) * r9 vector number isr_r9 (cr25) * * Fix them */ mfctl isr_arg0,%r3 stw %r3,ARG0_OFFSET(sp) mfctl isr_r9,%r3 stw %r3,R9_OFFSET(sp)/* * At this point we are done with isr_arg0, and isr_r9 control registers * * Prepare to re-enter virtual mode * We need Q in case the interrupt handler enables interrupts */ ldil L%CPU_PSW_DEFAULT, arg0 ldo R%CPU_PSW_DEFAULT(arg0), arg0 mtctl arg0, ipsw/* * Now jump to "rest_of_isr_handler" with the rfi * We are assuming the space queues are all correct already */ ldil L%rest_of_isr_handler, arg0 ldo R%rest_of_isr_handler(arg0), arg0 mtctl arg0, pcoq ldo 4(arg0), arg0 mtctl arg0, pcoq rfi nop/* * At this point we are back in virtual mode and all our * normal addressing is once again ok. * * It is now ok to take an exception or trap */rest_of_isr_handler:/* * Point to beginning of float context and * save the floating point context -- doing whatever patches are necessary */ .call ARGW0=GR bl _CPU_Save_float_context,%r2 ldo FP_CONTEXT_OFFSET(sp),arg0/* * save the ptr to interrupt frame as an argument for the interrupt handler */ copy sp, arg1/* * Advance the frame to point beyond all interrupt contexts (integer & float) * this also includes the pad to align to 64byte stack boundary */ ldo CPU_INTERRUPT_FRAME_SIZE(sp), sp/* * r3 -- &_ISR_Nest_level * r5 -- value _ISR_Nest_level * r4 -- &_Thread_Dispatch_disable_level * r6 -- value _Thread_Dispatch_disable_level * r9 -- vector number */ .import _ISR_Nest_level,data ldil L%_ISR_Nest_level,%r3 ldo R%_ISR_Nest_level(%r3),%r3 ldw 0(%r3),%r5 .import _Thread_Dispatch_disable_level,data ldil L%_Thread_Dispatch_disable_level,%r4 ldo R%_Thread_Dispatch_disable_level(%r4),%r4 ldw 0(%r4),%r6/* * increment interrupt nest level counter. If outermost interrupt * switch the stack and squirrel away the previous sp. */ addi 1,%r5,%r5 stw %r5, 0(%r3)/* * compute and save new stack (with frame) * just in case we are nested -- simpler this way */ comibf,= 1,%r5,stack_done ldo 128(sp),%r7/* * Switch to interrupt stack allocated by the interrupt manager (intr.c) */ .import _CPU_Interrupt_stack_low,data ldil L%_CPU_Interrupt_stack_low,%r7 ldw R%_CPU_Interrupt_stack_low(%r7),%r7 ldo 128(%r7),%r7stack_done:/* * save our current stack pointer where the "old sp" is supposed to be */ stw sp, -4(%r7)/* * and switch stacks (or advance old stack in nested case) */ copy %r7, sp/* * increment the dispatch disable level counter. */ addi 1,%r6,%r6 stw %r6, 0(%r4)/* * load address of user handler * Note: No error checking is done, it is assumed that the * vector table contains a valid address or a stub * spurious handler. */ .import _ISR_Vector_table,data ldil L%_ISR_Vector_table,%r8 ldo R%_ISR_Vector_table(%r8),%r8 ldw 0(%r8),%r8 ldwx,s %r9(%r8),%r8/* * invoke user interrupt handler * Interrupts are currently disabled, as per RTEMS convention * The handler has the option of re-enabling interrupts * NOTE: can not use 'bl' since it uses "pc-relative" addressing * and we are using a hard coded address from a table * So... we fudge r2 ourselves (ala dynacall) * arg0 = vector number, arg1 = ptr to rtems_interrupt_frame */ copy %r9, %r26 .call ARGW0=GR, ARGW1=GR blr %r0, rp bv,n 0(%r8)post_user_interrupt_handler:/* * Back from user handler(s) * Disable external interrupts (since the interrupt handler could * have turned them on) and return to the interrupted task stack (assuming * (_ISR_Nest_level == 0) */ rsm HPPA_PSW_I + HPPA_PSW_R, %r0 ldw -4(sp), sp/* * r3 -- (most of) &_ISR_Nest_level * r5 -- value _ISR_Nest_level * r4 -- (most of) &_Thread_Dispatch_disable_level * r6 -- value _Thread_Dispatch_disable_level * r7 -- (most of) &_ISR_Signals_to_thread_executing * r8 -- value _ISR_Signals_to_thread_executing */ .import _ISR_Nest_level,data ldil L%_ISR_Nest_level,%r3 ldw R%_ISR_Nest_level(%r3),%r5 .import _Thread_Dispatch_disable_level,data ldil L%_Thread_Dispatch_disable_level,%r4 ldw R%_Thread_Dispatch_disable_level(%r4),%r6 .import _ISR_Signals_to_thread_executing,data ldil L%_ISR_Signals_to_thread_executing,%r7/* * decrement isr nest level */ addi -1, %r5, %r5 stw %r5, R%_ISR_Nest_level(%r3)/* * decrement dispatch disable level counter and, if not 0, go on */ addi -1,%r6,%r6 comibf,= 0,%r6,isr_restore stw %r6, R%_Thread_Dispatch_disable_level(%r4)/* * check whether or not a context switch is necessary
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -