1272 lines · 33.7 KB · Assembly
RawDownload
/* SPDX-License-Identifier: GPL-2.0-or-later *//* * OpenRISC entry.S * * Linux architectural port borrowing liberally from similar works of * others.  All original copyrights apply as per the original source * declaration. * * Modifications for the OpenRISC architecture: * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com> * Copyright (C) 2005 Gyorgy Jeney <nog@bsemi.com> * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se> */ #include <linux/linkage.h>#include <linux/pgtable.h> #include <asm/processor.h>#include <asm/unistd.h>#include <asm/thread_info.h>#include <asm/errno.h>#include <asm/spr_defs.h>#include <asm/page.h>#include <asm/mmu.h>#include <asm/asm-offsets.h> #define DISABLE_INTERRUPTS(t1,t2)			\	l.mfspr t2,r0,SPR_SR				;\	l.movhi	t1,hi(~(SPR_SR_IEE|SPR_SR_TEE))		;\	l.ori	t1,t1,lo(~(SPR_SR_IEE|SPR_SR_TEE))	;\	l.and   t2,t2,t1				;\	l.mtspr r0,t2,SPR_SR #define ENABLE_INTERRUPTS(t1)				\	l.mfspr	t1,r0,SPR_SR				;\	l.ori	t1,t1,lo(SPR_SR_IEE|SPR_SR_TEE)		;\	l.mtspr	r0,t1,SPR_SR /* =========================================================[ macros ]=== */ #ifdef CONFIG_TRACE_IRQFLAGS/* * Trace irq on/off creating a stack frame. */#define TRACE_IRQS_OP(trace_op)					\	l.sw 	-8(r1),r2	/* store frame pointer */		;\	l.sw	-4(r1),r9	/* store return address */		;\	l.addi	r2,r1,0		/* move sp to fp */			;\	l.jal	trace_op						;\	 l.addi	r1,r1,-8						;\	l.ori	r1,r2,0		/* restore sp */			;\	l.lwz	r9,-4(r1)	/* restore return address */		;\	l.lwz	r2,-8(r1)	/* restore fp */			;\/* * Trace irq on/off and save registers we need that would otherwise be * clobbered. */#define TRACE_IRQS_SAVE(t1,trace_op)					\	l.sw	-12(r1),t1	/* save extra reg */			;\	l.sw 	-8(r1),r2	/* store frame pointer */		;\	l.sw	-4(r1),r9	/* store return address */		;\	l.addi	r2,r1,0		/* move sp to fp */			;\	l.jal	trace_op						;\	 l.addi	r1,r1,-12						;\	l.ori	r1,r2,0		/* restore sp */			;\	l.lwz	r9,-4(r1)	/* restore return address */		;\	l.lwz	r2,-8(r1)	/* restore fp */			;\	l.lwz	t1,-12(r1)	/* restore extra reg */ #define TRACE_IRQS_OFF	TRACE_IRQS_OP(trace_hardirqs_off)#define TRACE_IRQS_ON	TRACE_IRQS_OP(trace_hardirqs_on)#define TRACE_IRQS_ON_SYSCALL						\	TRACE_IRQS_SAVE(r10,trace_hardirqs_on)				;\	l.lwz	r3,PT_GPR3(r1)						;\	l.lwz	r4,PT_GPR4(r1)						;\	l.lwz	r5,PT_GPR5(r1)						;\	l.lwz	r6,PT_GPR6(r1)						;\	l.lwz	r7,PT_GPR7(r1)						;\	l.lwz	r8,PT_GPR8(r1)						;\	l.lwz	r11,PT_GPR11(r1)#define TRACE_IRQS_OFF_ENTRY						\	l.lwz	r5,PT_SR(r1)						;\	l.andi	r3,r5,(SPR_SR_IEE|SPR_SR_TEE)				;\	l.sfeq	r5,r0		/* skip trace if irqs were already off */;\	l.bf	1f							;\	 l.nop								;\	TRACE_IRQS_SAVE(r4,trace_hardirqs_off)				;\1:#else#define TRACE_IRQS_OFF#define TRACE_IRQS_ON#define TRACE_IRQS_OFF_ENTRY#define TRACE_IRQS_ON_SYSCALL#endif /* * We need to disable interrupts at beginning of RESTORE_ALL * since interrupt might come in after we've loaded EPC return address * and overwrite EPC with address somewhere in RESTORE_ALL * which is of course wrong! */ #define RESTORE_ALL						\	DISABLE_INTERRUPTS(r3,r4)				;\	l.lwz   r3,PT_PC(r1)					;\	l.mtspr r0,r3,SPR_EPCR_BASE				;\	l.lwz   r3,PT_SR(r1)					;\	l.mtspr r0,r3,SPR_ESR_BASE				;\	l.lwz   r2,PT_GPR2(r1)					;\	l.lwz   r3,PT_GPR3(r1)					;\	l.lwz   r4,PT_GPR4(r1)					;\	l.lwz   r5,PT_GPR5(r1)					;\	l.lwz   r6,PT_GPR6(r1)					;\	l.lwz   r7,PT_GPR7(r1)					;\	l.lwz   r8,PT_GPR8(r1)					;\	l.lwz   r9,PT_GPR9(r1)					;\	l.lwz   r10,PT_GPR10(r1)					;\	l.lwz   r11,PT_GPR11(r1)					;\	l.lwz   r12,PT_GPR12(r1)					;\	l.lwz   r13,PT_GPR13(r1)					;\	l.lwz   r14,PT_GPR14(r1)					;\	l.lwz   r15,PT_GPR15(r1)					;\	l.lwz   r16,PT_GPR16(r1)					;\	l.lwz   r17,PT_GPR17(r1)					;\	l.lwz   r18,PT_GPR18(r1)					;\	l.lwz   r19,PT_GPR19(r1)					;\	l.lwz   r20,PT_GPR20(r1)					;\	l.lwz   r21,PT_GPR21(r1)					;\	l.lwz   r22,PT_GPR22(r1)					;\	l.lwz   r23,PT_GPR23(r1)					;\	l.lwz   r24,PT_GPR24(r1)					;\	l.lwz   r25,PT_GPR25(r1)					;\	l.lwz   r26,PT_GPR26(r1)					;\	l.lwz   r27,PT_GPR27(r1)					;\	l.lwz   r28,PT_GPR28(r1)					;\	l.lwz   r29,PT_GPR29(r1)					;\	l.lwz   r30,PT_GPR30(r1)					;\	l.lwz   r31,PT_GPR31(r1)					;\	l.lwz   r1,PT_SP(r1)					;\	l.rfe  #define EXCEPTION_ENTRY(handler)				\	.global	handler						;\handler:							;\	/* r1, EPCR, ESR a already saved */			;\	l.sw	PT_GPR2(r1),r2					;\	l.sw    PT_GPR3(r1),r3					;\	/* r4 already save */					;\	l.sw    PT_GPR5(r1),r5					;\	l.sw    PT_GPR6(r1),r6					;\	l.sw    PT_GPR7(r1),r7					;\	l.sw    PT_GPR8(r1),r8					;\	l.sw    PT_GPR9(r1),r9					;\	/* r10 already saved */					;\	l.sw    PT_GPR11(r1),r11					;\	/* r12 already saved */					;\	l.sw    PT_GPR13(r1),r13					;\	l.sw    PT_GPR14(r1),r14					;\	l.sw    PT_GPR15(r1),r15					;\	l.sw    PT_GPR16(r1),r16					;\	l.sw    PT_GPR17(r1),r17					;\	l.sw    PT_GPR18(r1),r18					;\	l.sw    PT_GPR19(r1),r19					;\	l.sw    PT_GPR20(r1),r20					;\	l.sw    PT_GPR21(r1),r21					;\	l.sw    PT_GPR22(r1),r22					;\	l.sw    PT_GPR23(r1),r23					;\	l.sw    PT_GPR24(r1),r24					;\	l.sw    PT_GPR25(r1),r25					;\	l.sw    PT_GPR26(r1),r26					;\	l.sw    PT_GPR27(r1),r27					;\	l.sw    PT_GPR28(r1),r28					;\	l.sw    PT_GPR29(r1),r29					;\	/* r30 already save */					;\	l.sw    PT_GPR31(r1),r31					;\	TRACE_IRQS_OFF_ENTRY						;\	/* Store -1 in orig_gpr11 for non-syscall exceptions */	;\	l.addi	r30,r0,-1					;\	l.sw	PT_ORIG_GPR11(r1),r30 #define UNHANDLED_EXCEPTION(handler,vector)			\	.global	handler						;\handler:							;\	/* r1, EPCR, ESR already saved */			;\	l.sw    PT_GPR2(r1),r2					;\	l.sw    PT_GPR3(r1),r3					;\	l.sw    PT_GPR5(r1),r5					;\	l.sw    PT_GPR6(r1),r6					;\	l.sw    PT_GPR7(r1),r7					;\	l.sw    PT_GPR8(r1),r8					;\	l.sw    PT_GPR9(r1),r9					;\	/* r10 already saved */					;\	l.sw    PT_GPR11(r1),r11					;\	/* r12 already saved */					;\	l.sw    PT_GPR13(r1),r13					;\	l.sw    PT_GPR14(r1),r14					;\	l.sw    PT_GPR15(r1),r15					;\	l.sw    PT_GPR16(r1),r16					;\	l.sw    PT_GPR17(r1),r17					;\	l.sw    PT_GPR18(r1),r18					;\	l.sw    PT_GPR19(r1),r19					;\	l.sw    PT_GPR20(r1),r20					;\	l.sw    PT_GPR21(r1),r21					;\	l.sw    PT_GPR22(r1),r22					;\	l.sw    PT_GPR23(r1),r23					;\	l.sw    PT_GPR24(r1),r24					;\	l.sw    PT_GPR25(r1),r25					;\	l.sw    PT_GPR26(r1),r26					;\	l.sw    PT_GPR27(r1),r27					;\	l.sw    PT_GPR28(r1),r28					;\	l.sw    PT_GPR29(r1),r29					;\	/* r30 already saved */						;\	l.sw    PT_GPR31(r1),r31					;\	/* Store -1 in orig_gpr11 for non-syscall exceptions */	;\	l.addi	r30,r0,-1					;\	l.sw	PT_ORIG_GPR11(r1),r30				;\	l.addi	r3,r1,0						;\	/* r4 is exception EA */				;\	l.addi	r5,r0,vector					;\	l.jal	unhandled_exception				;\	 l.nop							;\	l.j	_ret_from_exception				;\	 l.nop /* clobbers 'reg' */#define CLEAR_LWA_FLAG(reg)		\	l.movhi	reg,hi(lwa_flag)	;\	l.ori	reg,reg,lo(lwa_flag)	;\	l.sw	0(reg),r0/* * NOTE: one should never assume that SPR_EPC, SPR_ESR, SPR_EEAR *       contain the same values as when exception we're handling *	 occured. in fact they never do. if you need them use *	 values saved on stack (for SPR_EPC, SPR_ESR) or content *       of r4 (for SPR_EEAR). for details look at EXCEPTION_HANDLE() *       in 'arch/openrisc/kernel/head.S' */ /* =====================================================[ exceptions] === */ 	__REF /* ---[ 0x100: RESET exception ]----------------------------------------- */ EXCEPTION_ENTRY(_tng_kernel_start)	l.jal	_start	 l.andi r0,r0,0 /* ---[ 0x200: BUS exception ]------------------------------------------- */ EXCEPTION_ENTRY(_bus_fault_handler)	CLEAR_LWA_FLAG(r3)	/* r4: EA of fault (set by EXCEPTION_HANDLE) */	l.jal   do_bus_fault	 l.addi  r3,r1,0 /* pt_regs */ 	l.j     _ret_from_exception	 l.nop /* ---[ 0x300: Data Page Fault exception ]------------------------------- */EXCEPTION_ENTRY(_dtlb_miss_page_fault_handler)	CLEAR_LWA_FLAG(r3)	l.and	r5,r5,r0	l.j	1f	 l.nop EXCEPTION_ENTRY(_data_page_fault_handler)	CLEAR_LWA_FLAG(r3)	/* set up parameters for do_page_fault */	l.ori	r5,r0,0x300		   // exception vector1:	l.addi  r3,r1,0                    // pt_regs	/* r4 set be EXCEPTION_HANDLE */   // effective address of fault #ifdef CONFIG_OPENRISC_NO_SPR_SR_DSX	l.lwz   r6,PT_PC(r3)               // address of an offending insn	l.lwz   r6,0(r6)                   // instruction that caused pf 	l.srli  r6,r6,26                   // check opcode for jump insn	l.sfeqi r6,0                       // l.j	l.bf    8f	l.sfeqi r6,1                       // l.jal	l.bf    8f	l.sfeqi r6,3                       // l.bnf	l.bf    8f	l.sfeqi r6,4                       // l.bf	l.bf    8f	l.sfeqi r6,0x11                    // l.jr	l.bf    8f	l.sfeqi r6,0x12                    // l.jalr	l.bf    8f	 l.nop 	l.j     9f	 l.nop 8: // offending insn is in delay slot	l.lwz   r6,PT_PC(r3)               // address of an offending insn	l.addi  r6,r6,4	l.lwz   r6,0(r6)                   // instruction that caused pf	l.srli  r6,r6,26                   // get opcode9: // offending instruction opcode loaded in r6 #else 	l.mfspr r6,r0,SPR_SR               // SR	l.andi  r6,r6,SPR_SR_DSX           // check for delay slot exception	l.sfne  r6,r0                      // exception happened in delay slot	l.bnf   7f	 l.lwz  r6,PT_PC(r3)               // address of an offending insn 	l.addi	r6,r6,4                    // offending insn is in delay slot7:	l.lwz   r6,0(r6)                   // instruction that caused pf	l.srli  r6,r6,26                   // check opcode for write access#endif 	l.sfgeui r6,0x33                   // check opcode for write access	l.bnf   1f	l.sfleui r6,0x37	l.bnf   1f	l.ori   r6,r0,0x1                  // write access	l.j     2f	 l.nop1:	l.ori   r6,r0,0x0                  // !write access2: 	/* call fault.c handler in openrisc/mm/fault.c */	l.jal   do_page_fault	 l.nop	l.j     _ret_from_exception	 l.nop /* ---[ 0x400: Insn Page Fault exception ]------------------------------- */EXCEPTION_ENTRY(_itlb_miss_page_fault_handler)	CLEAR_LWA_FLAG(r3)	l.and	r5,r5,r0	l.j	1f	 l.nop EXCEPTION_ENTRY(_insn_page_fault_handler)	CLEAR_LWA_FLAG(r3)	/* set up parameters for do_page_fault */	l.ori	r5,r0,0x400		   // exception vector1:	l.addi  r3,r1,0                    // pt_regs	/* r4 set be EXCEPTION_HANDLE */   // effective address of fault	l.ori	r6,r0,0x0		   // !write access 	/* call fault.c handler in openrisc/mm/fault.c */	l.jal   do_page_fault	 l.nop	l.j     _ret_from_exception	 l.nop  /* ---[ 0x500: Timer exception ]----------------------------------------- */ EXCEPTION_ENTRY(_timer_handler)	CLEAR_LWA_FLAG(r3)	l.jal	timer_interrupt	 l.addi r3,r1,0 /* pt_regs */ 	l.j    _ret_from_intr	 l.nop /* ---[ 0x600: Alignment exception ]-------------------------------------- */ EXCEPTION_ENTRY(_alignment_handler)	CLEAR_LWA_FLAG(r3)	/* r4: EA of fault (set by EXCEPTION_HANDLE) */	l.jal   do_unaligned_access	 l.addi  r3,r1,0 /* pt_regs */ 	l.j     _ret_from_exception	 l.nop #if 0EXCEPTION_ENTRY(_alignment_handler)//        l.mfspr r2,r0,SPR_EEAR_BASE     /* Load the effective address */	l.addi	r2,r4,0//        l.mfspr r5,r0,SPR_EPCR_BASE     /* Load the insn address */	l.lwz   r5,PT_PC(r1) 	l.lwz   r3,0(r5)                /* Load insn */	l.srli  r4,r3,26                /* Shift left to get the insn opcode */ 	l.sfeqi r4,0x00                 /* Check if the load/store insn is in delay slot */	l.bf    jmp	l.sfeqi r4,0x01	l.bf    jmp	l.sfeqi r4,0x03	l.bf    jmp	l.sfeqi r4,0x04	l.bf    jmp	l.sfeqi r4,0x11	l.bf    jr	l.sfeqi r4,0x12	l.bf    jr	l.nop	l.j     1f	l.addi  r5,r5,4                 /* Increment PC to get return insn address */ jmp:	l.slli  r4,r3,6                 /* Get the signed extended jump length */	l.srai  r4,r4,4 	l.lwz   r3,4(r5)                /* Load the real load/store insn */ 	l.add   r5,r5,r4                /* Calculate jump target address */ 	l.j     1f	l.srli  r4,r3,26                /* Shift left to get the insn opcode */ jr:	l.slli  r4,r3,9                 /* Shift to get the reg nb */	l.andi  r4,r4,0x7c 	l.lwz   r3,4(r5)                /* Load the real load/store insn */ 	l.add   r4,r4,r1                /* Load the jump register value from the stack */	l.lwz   r5,0(r4) 	l.srli  r4,r3,26                /* Shift left to get the insn opcode */  1://	  l.mtspr r0,r5,SPR_EPCR_BASE	l.sw	PT_PC(r1),r5 	l.sfeqi r4,0x26	l.bf    lhs	l.sfeqi r4,0x25	l.bf    lhz	l.sfeqi r4,0x22	l.bf    lws	l.sfeqi r4,0x21	l.bf    lwz	l.sfeqi r4,0x37	l.bf    sh	l.sfeqi r4,0x35	l.bf    sw	l.nop 1:      l.j     1b                      /* I don't know what to do */	l.nop lhs:    l.lbs   r5,0(r2)	l.slli  r5,r5,8	l.lbz   r6,1(r2)	l.or    r5,r5,r6	l.srli  r4,r3,19	l.andi  r4,r4,0x7c	l.add   r4,r4,r1	l.j     align_end	l.sw    0(r4),r5 lhz:    l.lbz   r5,0(r2)	l.slli  r5,r5,8	l.lbz   r6,1(r2)	l.or    r5,r5,r6	l.srli  r4,r3,19	l.andi  r4,r4,0x7c	l.add   r4,r4,r1	l.j     align_end	l.sw    0(r4),r5 lws:    l.lbs   r5,0(r2)	l.slli  r5,r5,24	l.lbz   r6,1(r2)	l.slli  r6,r6,16	l.or    r5,r5,r6	l.lbz   r6,2(r2)	l.slli  r6,r6,8	l.or    r5,r5,r6	l.lbz   r6,3(r2)	l.or    r5,r5,r6	l.srli  r4,r3,19	l.andi  r4,r4,0x7c	l.add   r4,r4,r1	l.j     align_end	l.sw    0(r4),r5 lwz:    l.lbz   r5,0(r2)	l.slli  r5,r5,24	l.lbz   r6,1(r2)	l.slli  r6,r6,16	l.or    r5,r5,r6	l.lbz   r6,2(r2)	l.slli  r6,r6,8	l.or    r5,r5,r6	l.lbz   r6,3(r2)	l.or    r5,r5,r6	l.srli  r4,r3,19	l.andi  r4,r4,0x7c	l.add   r4,r4,r1	l.j     align_end	l.sw    0(r4),r5 

Lines 1–500 of 1272.