Path: blob/master/arch/microblaze/kernel/entry-nommu.S
10817 views
/*1* Copyright (C) 2007-2009 Michal Simek <[email protected]>2* Copyright (C) 2007-2009 PetaLogix3* Copyright (C) 2006 Atmark Techno, Inc.4*5* This file is subject to the terms and conditions of the GNU General Public6* License. See the file "COPYING" in the main directory of this archive7* for more details.8*/910#include <linux/linkage.h>11#include <asm/thread_info.h>12#include <linux/errno.h>13#include <asm/entry.h>14#include <asm/asm-offsets.h>15#include <asm/registers.h>16#include <asm/unistd.h>17#include <asm/percpu.h>18#include <asm/signal.h>1920#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR21.macro disable_irq22msrclr r0, MSR_IE23.endm2425.macro enable_irq26msrset r0, MSR_IE27.endm2829.macro clear_bip30msrclr r0, MSR_BIP31.endm32#else33.macro disable_irq34mfs r11, rmsr35andi r11, r11, ~MSR_IE36mts rmsr, r1137.endm3839.macro enable_irq40mfs r11, rmsr41ori r11, r11, MSR_IE42mts rmsr, r1143.endm4445.macro clear_bip46mfs r11, rmsr47andi r11, r11, ~MSR_BIP48mts rmsr, r1149.endm50#endif5152ENTRY(_interrupt)53swi r1, r0, PER_CPU(ENTRY_SP) /* save the current sp */54swi r11, r0, PER_CPU(R11_SAVE) /* temporarily save r11 */55lwi r11, r0, PER_CPU(KM) /* load mode indicator */56beqid r11, 1f57nop58brid 2f /* jump over */59addik r1, r1, (-PT_SIZE) /* room for pt_regs (delay slot) */601: /* switch to kernel stack */61lwi r1, r0, PER_CPU(CURRENT_SAVE) /* get the saved current */62lwi r1, r1, TS_THREAD_INFO /* get the thread info */63/* calculate kernel stack pointer */64addik r1, r1, THREAD_SIZE - PT_SIZE652:66swi r11, r1, PT_MODE /* store the mode */67lwi r11, r0, PER_CPU(R11_SAVE) /* reload r11 */68swi r2, r1, PT_R269swi r3, r1, PT_R370swi r4, r1, PT_R471swi r5, r1, PT_R572swi r6, r1, PT_R673swi r7, r1, PT_R774swi r8, r1, PT_R875swi r9, r1, PT_R976swi r10, r1, PT_R1077swi r11, r1, PT_R1178swi r12, r1, PT_R1279swi r13, r1, PT_R1380swi r14, r1, PT_R1481swi r14, r1, PT_PC82swi r15, r1, PT_R1583swi r16, r1, PT_R1684swi r17, r1, PT_R1785swi r18, r1, PT_R1886swi r19, r1, PT_R1987swi r20, r1, PT_R2088swi r21, r1, PT_R2189swi r22, r1, PT_R2290swi r23, r1, PT_R2391swi r24, r1, PT_R2492swi r25, r1, PT_R2593swi r26, r1, PT_R2694swi r27, r1, PT_R2795swi r28, r1, PT_R2896swi r29, r1, PT_R2997swi r30, r1, PT_R3098swi r31, r1, PT_R3199/* special purpose registers */100mfs r11, rmsr101swi r11, r1, PT_MSR102mfs r11, rear103swi r11, r1, PT_EAR104mfs r11, resr105swi r11, r1, PT_ESR106mfs r11, rfsr107swi r11, r1, PT_FSR108/* reload original stack pointer and save it */109lwi r11, r0, PER_CPU(ENTRY_SP)110swi r11, r1, PT_R1111/* update mode indicator we are in kernel mode */112addik r11, r0, 1113swi r11, r0, PER_CPU(KM)114/* restore r31 */115lwi r31, r0, PER_CPU(CURRENT_SAVE)116/* prepare the link register, the argument and jump */117addik r15, r0, ret_from_intr - 8118addk r6, r0, r15119braid do_IRQ120add r5, r0, r1121122ret_from_intr:123lwi r11, r1, PT_MODE124bneid r11, no_intr_resched125126lwi r6, r31, TS_THREAD_INFO /* get thread info */127lwi r19, r6, TI_FLAGS /* get flags in thread info */128/* do an extra work if any bits are set */129130andi r11, r19, _TIF_NEED_RESCHED131beqi r11, 1f132bralid r15, schedule133nop1341: andi r11, r19, _TIF_SIGPENDING135beqid r11, no_intr_resched136addk r5, r1, r0137addk r7, r0, r0138bralid r15, do_signal139addk r6, r0, r0140141no_intr_resched:142/* Disable interrupts, we are now committed to the state restore */143disable_irq144145/* save mode indicator */146lwi r11, r1, PT_MODE147swi r11, r0, PER_CPU(KM)148149/* save r31 */150swi r31, r0, PER_CPU(CURRENT_SAVE)151restore_context:152/* special purpose registers */153lwi r11, r1, PT_FSR154mts rfsr, r11155lwi r11, r1, PT_ESR156mts resr, r11157lwi r11, r1, PT_EAR158mts rear, r11159lwi r11, r1, PT_MSR160mts rmsr, r11161162lwi r31, r1, PT_R31163lwi r30, r1, PT_R30164lwi r29, r1, PT_R29165lwi r28, r1, PT_R28166lwi r27, r1, PT_R27167lwi r26, r1, PT_R26168lwi r25, r1, PT_R25169lwi r24, r1, PT_R24170lwi r23, r1, PT_R23171lwi r22, r1, PT_R22172lwi r21, r1, PT_R21173lwi r20, r1, PT_R20174lwi r19, r1, PT_R19175lwi r18, r1, PT_R18176lwi r17, r1, PT_R17177lwi r16, r1, PT_R16178lwi r15, r1, PT_R15179lwi r14, r1, PT_PC180lwi r13, r1, PT_R13181lwi r12, r1, PT_R12182lwi r11, r1, PT_R11183lwi r10, r1, PT_R10184lwi r9, r1, PT_R9185lwi r8, r1, PT_R8186lwi r7, r1, PT_R7187lwi r6, r1, PT_R6188lwi r5, r1, PT_R5189lwi r4, r1, PT_R4190lwi r3, r1, PT_R3191lwi r2, r1, PT_R2192lwi r1, r1, PT_R1193rtid r14, 0194nop195196ENTRY(_reset)197brai 0;198199ENTRY(_user_exception)200swi r1, r0, PER_CPU(ENTRY_SP) /* save the current sp */201swi r11, r0, PER_CPU(R11_SAVE) /* temporarily save r11 */202lwi r11, r0, PER_CPU(KM) /* load mode indicator */203beqid r11, 1f /* Already in kernel mode? */204nop205brid 2f /* jump over */206addik r1, r1, (-PT_SIZE) /* Room for pt_regs (delay slot) */2071: /* Switch to kernel stack */208lwi r1, r0, PER_CPU(CURRENT_SAVE) /* get the saved current */209lwi r1, r1, TS_THREAD_INFO /* get the thread info */210/* calculate kernel stack pointer */211addik r1, r1, THREAD_SIZE - PT_SIZE2122:213swi r11, r1, PT_MODE /* store the mode */214lwi r11, r0, PER_CPU(R11_SAVE) /* reload r11 */215/* save them on stack */216swi r2, r1, PT_R2217swi r3, r1, PT_R3 /* r3: _always_ in clobber list; see unistd.h */218swi r4, r1, PT_R4 /* r4: _always_ in clobber list; see unistd.h */219swi r5, r1, PT_R5220swi r6, r1, PT_R6221swi r7, r1, PT_R7222swi r8, r1, PT_R8223swi r9, r1, PT_R9224swi r10, r1, PT_R10225swi r11, r1, PT_R11226/* r12: _always_ in clobber list; see unistd.h */227swi r12, r1, PT_R12228swi r13, r1, PT_R13229/* r14: _always_ in clobber list; see unistd.h */230swi r14, r1, PT_R14231/* but we want to return to the next inst. */232addik r14, r14, 0x4233swi r14, r1, PT_PC /* increment by 4 and store in pc */234swi r15, r1, PT_R15235swi r16, r1, PT_R16236swi r17, r1, PT_R17237swi r18, r1, PT_R18238swi r19, r1, PT_R19239swi r20, r1, PT_R20240swi r21, r1, PT_R21241swi r22, r1, PT_R22242swi r23, r1, PT_R23243swi r24, r1, PT_R24244swi r25, r1, PT_R25245swi r26, r1, PT_R26246swi r27, r1, PT_R27247swi r28, r1, PT_R28248swi r29, r1, PT_R29249swi r30, r1, PT_R30250swi r31, r1, PT_R31251252disable_irq253nop /* make sure IE bit is in effect */254clear_bip /* once IE is in effect it is safe to clear BIP */255nop256257/* special purpose registers */258mfs r11, rmsr259swi r11, r1, PT_MSR260mfs r11, rear261swi r11, r1, PT_EAR262mfs r11, resr263swi r11, r1, PT_ESR264mfs r11, rfsr265swi r11, r1, PT_FSR266/* reload original stack pointer and save it */267lwi r11, r0, PER_CPU(ENTRY_SP)268swi r11, r1, PT_R1269/* update mode indicator we are in kernel mode */270addik r11, r0, 1271swi r11, r0, PER_CPU(KM)272/* restore r31 */273lwi r31, r0, PER_CPU(CURRENT_SAVE)274/* re-enable interrupts now we are in kernel mode */275enable_irq276277/* See if the system call number is valid. */278addi r11, r12, -__NR_syscalls279bgei r11, 1f /* return to user if not valid */280/* Figure out which function to use for this system call. */281/* Note Microblaze barrel shift is optional, so don't rely on it */282add r12, r12, r12 /* convert num -> ptr */283add r12, r12, r12284lwi r12, r12, sys_call_table /* Get function pointer */285addik r15, r0, ret_to_user-8 /* set return address */286bra r12 /* Make the system call. */287bri 0 /* won't reach here */2881:289brid ret_to_user /* jump to syscall epilogue */290addi r3, r0, -ENOSYS /* set errno in delay slot */291292/*293* Debug traps are like a system call, but entered via brki r14, 0x60294* All we need to do is send the SIGTRAP signal to current, ptrace and do_signal295* will handle the rest296*/297ENTRY(_debug_exception)298swi r1, r0, PER_CPU(ENTRY_SP) /* save the current sp */299lwi r1, r0, PER_CPU(CURRENT_SAVE) /* get the saved current */300lwi r1, r1, TS_THREAD_INFO /* get the thread info */301addik r1, r1, THREAD_SIZE - PT_SIZE /* get the kernel stack */302swi r11, r0, PER_CPU(R11_SAVE) /* temporarily save r11 */303lwi r11, r0, PER_CPU(KM) /* load mode indicator */304//save_context:305swi r11, r1, PT_MODE /* store the mode */306lwi r11, r0, PER_CPU(R11_SAVE) /* reload r11 */307/* save them on stack */308swi r2, r1, PT_R2309swi r3, r1, PT_R3 /* r3: _always_ in clobber list; see unistd.h */310swi r4, r1, PT_R4 /* r4: _always_ in clobber list; see unistd.h */311swi r5, r1, PT_R5312swi r6, r1, PT_R6313swi r7, r1, PT_R7314swi r8, r1, PT_R8315swi r9, r1, PT_R9316swi r10, r1, PT_R10317swi r11, r1, PT_R11318/* r12: _always_ in clobber list; see unistd.h */319swi r12, r1, PT_R12320swi r13, r1, PT_R13321/* r14: _always_ in clobber list; see unistd.h */322swi r14, r1, PT_R14323swi r14, r1, PT_PC /* Will return to interrupted instruction */324swi r15, r1, PT_R15325swi r16, r1, PT_R16326swi r17, r1, PT_R17327swi r18, r1, PT_R18328swi r19, r1, PT_R19329swi r20, r1, PT_R20330swi r21, r1, PT_R21331swi r22, r1, PT_R22332swi r23, r1, PT_R23333swi r24, r1, PT_R24334swi r25, r1, PT_R25335swi r26, r1, PT_R26336swi r27, r1, PT_R27337swi r28, r1, PT_R28338swi r29, r1, PT_R29339swi r30, r1, PT_R30340swi r31, r1, PT_R31341342disable_irq343nop /* make sure IE bit is in effect */344clear_bip /* once IE is in effect it is safe to clear BIP */345nop346347/* special purpose registers */348mfs r11, rmsr349swi r11, r1, PT_MSR350mfs r11, rear351swi r11, r1, PT_EAR352mfs r11, resr353swi r11, r1, PT_ESR354mfs r11, rfsr355swi r11, r1, PT_FSR356/* reload original stack pointer and save it */357lwi r11, r0, PER_CPU(ENTRY_SP)358swi r11, r1, PT_R1359/* update mode indicator we are in kernel mode */360addik r11, r0, 1361swi r11, r0, PER_CPU(KM)362/* restore r31 */363lwi r31, r0, PER_CPU(CURRENT_SAVE)364/* re-enable interrupts now we are in kernel mode */365enable_irq366367addi r5, r0, SIGTRAP /* sending the trap signal */368add r6, r0, r31 /* to current */369bralid r15, send_sig370add r7, r0, r0 /* 3rd param zero */371372/* Restore r3/r4 to work around how ret_to_user works */373lwi r3, r1, PT_R3374lwi r4, r1, PT_R4375bri ret_to_user376377ENTRY(_break)378bri 0379380/* struct task_struct *_switch_to(struct thread_info *prev,381struct thread_info *next); */382ENTRY(_switch_to)383/* prepare return value */384addk r3, r0, r31385386/* save registers in cpu_context */387/* use r11 and r12, volatile registers, as temp register */388addik r11, r5, TI_CPU_CONTEXT389swi r1, r11, CC_R1390swi r2, r11, CC_R2391/* skip volatile registers.392* they are saved on stack when we jumped to _switch_to() */393/* dedicated registers */394swi r13, r11, CC_R13395swi r14, r11, CC_R14396swi r15, r11, CC_R15397swi r16, r11, CC_R16398swi r17, r11, CC_R17399swi r18, r11, CC_R18400/* save non-volatile registers */401swi r19, r11, CC_R19402swi r20, r11, CC_R20403swi r21, r11, CC_R21404swi r22, r11, CC_R22405swi r23, r11, CC_R23406swi r24, r11, CC_R24407swi r25, r11, CC_R25408swi r26, r11, CC_R26409swi r27, r11, CC_R27410swi r28, r11, CC_R28411swi r29, r11, CC_R29412swi r30, r11, CC_R30413/* special purpose registers */414mfs r12, rmsr415swi r12, r11, CC_MSR416mfs r12, rear417swi r12, r11, CC_EAR418mfs r12, resr419swi r12, r11, CC_ESR420mfs r12, rfsr421swi r12, r11, CC_FSR422423/* update r31, the current */424lwi r31, r6, TI_TASK425swi r31, r0, PER_CPU(CURRENT_SAVE)426427/* get new process' cpu context and restore */428addik r11, r6, TI_CPU_CONTEXT429430/* special purpose registers */431lwi r12, r11, CC_FSR432mts rfsr, r12433lwi r12, r11, CC_ESR434mts resr, r12435lwi r12, r11, CC_EAR436mts rear, r12437lwi r12, r11, CC_MSR438mts rmsr, r12439/* non-volatile registers */440lwi r30, r11, CC_R30441lwi r29, r11, CC_R29442lwi r28, r11, CC_R28443lwi r27, r11, CC_R27444lwi r26, r11, CC_R26445lwi r25, r11, CC_R25446lwi r24, r11, CC_R24447lwi r23, r11, CC_R23448lwi r22, r11, CC_R22449lwi r21, r11, CC_R21450lwi r20, r11, CC_R20451lwi r19, r11, CC_R19452/* dedicated registers */453lwi r18, r11, CC_R18454lwi r17, r11, CC_R17455lwi r16, r11, CC_R16456lwi r15, r11, CC_R15457lwi r14, r11, CC_R14458lwi r13, r11, CC_R13459/* skip volatile registers */460lwi r2, r11, CC_R2461lwi r1, r11, CC_R1462463rtsd r15, 8464nop465466ENTRY(ret_from_fork)467addk r5, r0, r3468addk r6, r0, r1469brlid r15, schedule_tail470nop471swi r31, r1, PT_R31 /* save r31 in user context. */472/* will soon be restored to r31 in ret_to_user */473addk r3, r0, r0474brid ret_to_user475nop476477work_pending:478enable_irq479480andi r11, r19, _TIF_NEED_RESCHED481beqi r11, 1f482bralid r15, schedule483nop4841: andi r11, r19, _TIF_SIGPENDING485beqi r11, no_work_pending486addk r5, r1, r0487addik r7, r0, 1488bralid r15, do_signal489addk r6, r0, r0490bri no_work_pending491492ENTRY(ret_to_user)493disable_irq494495swi r4, r1, PT_R4 /* return val */496swi r3, r1, PT_R3 /* return val */497498lwi r6, r31, TS_THREAD_INFO /* get thread info */499lwi r19, r6, TI_FLAGS /* get flags in thread info */500bnei r19, work_pending /* do an extra work if any bits are set */501no_work_pending:502disable_irq503504/* save r31 */505swi r31, r0, PER_CPU(CURRENT_SAVE)506/* save mode indicator */507lwi r18, r1, PT_MODE508swi r18, r0, PER_CPU(KM)509//restore_context:510/* special purpose registers */511lwi r18, r1, PT_FSR512mts rfsr, r18513lwi r18, r1, PT_ESR514mts resr, r18515lwi r18, r1, PT_EAR516mts rear, r18517lwi r18, r1, PT_MSR518mts rmsr, r18519520lwi r31, r1, PT_R31521lwi r30, r1, PT_R30522lwi r29, r1, PT_R29523lwi r28, r1, PT_R28524lwi r27, r1, PT_R27525lwi r26, r1, PT_R26526lwi r25, r1, PT_R25527lwi r24, r1, PT_R24528lwi r23, r1, PT_R23529lwi r22, r1, PT_R22530lwi r21, r1, PT_R21531lwi r20, r1, PT_R20532lwi r19, r1, PT_R19533lwi r18, r1, PT_R18534lwi r17, r1, PT_R17535lwi r16, r1, PT_R16536lwi r15, r1, PT_R15537lwi r14, r1, PT_PC538lwi r13, r1, PT_R13539lwi r12, r1, PT_R12540lwi r11, r1, PT_R11541lwi r10, r1, PT_R10542lwi r9, r1, PT_R9543lwi r8, r1, PT_R8544lwi r7, r1, PT_R7545lwi r6, r1, PT_R6546lwi r5, r1, PT_R5547lwi r4, r1, PT_R4 /* return val */548lwi r3, r1, PT_R3 /* return val */549lwi r2, r1, PT_R2550lwi r1, r1, PT_R1551552rtid r14, 0553nop554555sys_vfork:556brid microblaze_vfork557addk r5, r1, r0558559sys_clone:560brid microblaze_clone561addk r7, r1, r0562563sys_execve:564brid microblaze_execve565addk r8, r1, r0566567sys_rt_sigreturn_wrapper:568brid sys_rt_sigreturn569addk r5, r1, r0570571sys_rt_sigsuspend_wrapper:572brid sys_rt_sigsuspend573addk r7, r1, r0574575/* Interrupt vector table */576.section .init.ivt, "ax"577.org 0x0578brai _reset579brai _user_exception580brai _interrupt581brai _break582brai _hw_exception_handler583.org 0x60584brai _debug_exception585586.section .rodata,"a"587#include "syscall_table.S"588589syscall_table_size=(.-sys_call_table)590591type_SYSCALL:592.ascii "SYSCALL\0"593type_IRQ:594.ascii "IRQ\0"595type_IRQ_PREEMPT:596.ascii "IRQ (PREEMPTED)\0"597type_SYSCALL_PREEMPT:598.ascii " SYSCALL (PREEMPTED)\0"599600/*601* Trap decoding for stack unwinder602* Tuples are (start addr, end addr, string)603* If return address lies on [start addr, end addr],604* unwinder displays 'string'605*/606607.align 4608.global microblaze_trap_handlers609microblaze_trap_handlers:610/* Exact matches come first */611.word ret_to_user ; .word ret_to_user ; .word type_SYSCALL612.word ret_from_intr; .word ret_from_intr ; .word type_IRQ613/* Fuzzy matches go here */614.word ret_from_intr; .word no_intr_resched; .word type_IRQ_PREEMPT615.word work_pending ; .word no_work_pending; .word type_SYSCALL_PREEMPT616/* End of table */617.word 0 ; .word 0 ; .word 0618619620