12874c5fdSThomas Gleixner/* SPDX-License-Identifier: GPL-2.0-or-later */ 29d02a428SJonas Bonn/* 39d02a428SJonas Bonn * OpenRISC entry.S 49d02a428SJonas Bonn * 59d02a428SJonas Bonn * Linux architectural port borrowing liberally from similar works of 69d02a428SJonas Bonn * others. All original copyrights apply as per the original source 79d02a428SJonas Bonn * declaration. 89d02a428SJonas Bonn * 99d02a428SJonas Bonn * Modifications for the OpenRISC architecture: 109d02a428SJonas Bonn * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com> 119d02a428SJonas Bonn * Copyright (C) 2005 Gyorgy Jeney <nog@bsemi.com> 129d02a428SJonas Bonn * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se> 139d02a428SJonas Bonn */ 149d02a428SJonas Bonn 159d02a428SJonas Bonn#include <linux/linkage.h> 1665fddcfcSMike Rapoport#include <linux/pgtable.h> 179d02a428SJonas Bonn 189d02a428SJonas Bonn#include <asm/processor.h> 199d02a428SJonas Bonn#include <asm/unistd.h> 209d02a428SJonas Bonn#include <asm/thread_info.h> 219d02a428SJonas Bonn#include <asm/errno.h> 229d02a428SJonas Bonn#include <asm/spr_defs.h> 239d02a428SJonas Bonn#include <asm/page.h> 249d02a428SJonas Bonn#include <asm/mmu.h> 259d02a428SJonas Bonn#include <asm/asm-offsets.h> 269d02a428SJonas Bonn 279d02a428SJonas Bonn#define DISABLE_INTERRUPTS(t1,t2) \ 289d02a428SJonas Bonn l.mfspr t2,r0,SPR_SR ;\ 299d02a428SJonas Bonn l.movhi t1,hi(~(SPR_SR_IEE|SPR_SR_TEE)) ;\ 309d02a428SJonas Bonn l.ori t1,t1,lo(~(SPR_SR_IEE|SPR_SR_TEE)) ;\ 319d02a428SJonas Bonn l.and t2,t2,t1 ;\ 329d02a428SJonas Bonn l.mtspr r0,t2,SPR_SR 339d02a428SJonas Bonn 349d02a428SJonas Bonn#define ENABLE_INTERRUPTS(t1) \ 359d02a428SJonas Bonn l.mfspr t1,r0,SPR_SR ;\ 369d02a428SJonas Bonn l.ori t1,t1,lo(SPR_SR_IEE|SPR_SR_TEE) ;\ 379d02a428SJonas Bonn l.mtspr r0,t1,SPR_SR 389d02a428SJonas Bonn 399d02a428SJonas Bonn/* =========================================================[ macros ]=== */ 409d02a428SJonas Bonn 4178cdfb5cSStafford Horne#ifdef CONFIG_TRACE_IRQFLAGS 4278cdfb5cSStafford Horne/* 4378cdfb5cSStafford Horne * Trace irq on/off creating a stack frame. 4478cdfb5cSStafford Horne */ 4578cdfb5cSStafford Horne#define TRACE_IRQS_OP(trace_op) \ 4678cdfb5cSStafford Horne l.sw -8(r1),r2 /* store frame pointer */ ;\ 4778cdfb5cSStafford Horne l.sw -4(r1),r9 /* store return address */ ;\ 4878cdfb5cSStafford Horne l.addi r2,r1,0 /* move sp to fp */ ;\ 4978cdfb5cSStafford Horne l.jal trace_op ;\ 5078cdfb5cSStafford Horne l.addi r1,r1,-8 ;\ 5178cdfb5cSStafford Horne l.ori r1,r2,0 /* restore sp */ ;\ 5278cdfb5cSStafford Horne l.lwz r9,-4(r1) /* restore return address */ ;\ 5378cdfb5cSStafford Horne l.lwz r2,-8(r1) /* restore fp */ ;\ 5478cdfb5cSStafford Horne/* 5578cdfb5cSStafford Horne * Trace irq on/off and save registers we need that would otherwise be 5678cdfb5cSStafford Horne * clobbered. 5778cdfb5cSStafford Horne */ 5878cdfb5cSStafford Horne#define TRACE_IRQS_SAVE(t1,trace_op) \ 5978cdfb5cSStafford Horne l.sw -12(r1),t1 /* save extra reg */ ;\ 6078cdfb5cSStafford Horne l.sw -8(r1),r2 /* store frame pointer */ ;\ 6178cdfb5cSStafford Horne l.sw -4(r1),r9 /* store return address */ ;\ 6278cdfb5cSStafford Horne l.addi r2,r1,0 /* move sp to fp */ ;\ 6378cdfb5cSStafford Horne l.jal trace_op ;\ 6478cdfb5cSStafford Horne l.addi r1,r1,-12 ;\ 6578cdfb5cSStafford Horne l.ori r1,r2,0 /* restore sp */ ;\ 6678cdfb5cSStafford Horne l.lwz r9,-4(r1) /* restore return address */ ;\ 6778cdfb5cSStafford Horne l.lwz r2,-8(r1) /* restore fp */ ;\ 6878cdfb5cSStafford Horne l.lwz t1,-12(r1) /* restore extra reg */ 6978cdfb5cSStafford Horne 7078cdfb5cSStafford Horne#define TRACE_IRQS_OFF TRACE_IRQS_OP(trace_hardirqs_off) 7178cdfb5cSStafford Horne#define TRACE_IRQS_ON TRACE_IRQS_OP(trace_hardirqs_on) 7278cdfb5cSStafford Horne#define TRACE_IRQS_ON_SYSCALL \ 7378cdfb5cSStafford Horne TRACE_IRQS_SAVE(r10,trace_hardirqs_on) ;\ 7478cdfb5cSStafford Horne l.lwz r3,PT_GPR3(r1) ;\ 7578cdfb5cSStafford Horne l.lwz r4,PT_GPR4(r1) ;\ 7678cdfb5cSStafford Horne l.lwz r5,PT_GPR5(r1) ;\ 7778cdfb5cSStafford Horne l.lwz r6,PT_GPR6(r1) ;\ 7878cdfb5cSStafford Horne l.lwz r7,PT_GPR7(r1) ;\ 7978cdfb5cSStafford Horne l.lwz r8,PT_GPR8(r1) ;\ 8078cdfb5cSStafford Horne l.lwz r11,PT_GPR11(r1) 8178cdfb5cSStafford Horne#define TRACE_IRQS_OFF_ENTRY \ 8278cdfb5cSStafford Horne l.lwz r5,PT_SR(r1) ;\ 8378cdfb5cSStafford Horne l.andi r3,r5,(SPR_SR_IEE|SPR_SR_TEE) ;\ 8478cdfb5cSStafford Horne l.sfeq r5,r0 /* skip trace if irqs were already off */;\ 8578cdfb5cSStafford Horne l.bf 1f ;\ 8678cdfb5cSStafford Horne l.nop ;\ 8778cdfb5cSStafford Horne TRACE_IRQS_SAVE(r4,trace_hardirqs_off) ;\ 8878cdfb5cSStafford Horne1: 8978cdfb5cSStafford Horne#else 9078cdfb5cSStafford Horne#define TRACE_IRQS_OFF 9178cdfb5cSStafford Horne#define TRACE_IRQS_ON 9278cdfb5cSStafford Horne#define TRACE_IRQS_OFF_ENTRY 9378cdfb5cSStafford Horne#define TRACE_IRQS_ON_SYSCALL 9478cdfb5cSStafford Horne#endif 9578cdfb5cSStafford Horne 969d02a428SJonas Bonn/* 979d02a428SJonas Bonn * We need to disable interrupts at beginning of RESTORE_ALL 989d02a428SJonas Bonn * since interrupt might come in after we've loaded EPC return address 999d02a428SJonas Bonn * and overwrite EPC with address somewhere in RESTORE_ALL 1009d02a428SJonas Bonn * which is of course wrong! 1019d02a428SJonas Bonn */ 1029d02a428SJonas Bonn 1039d02a428SJonas Bonn#define RESTORE_ALL \ 1049d02a428SJonas Bonn DISABLE_INTERRUPTS(r3,r4) ;\ 1059d02a428SJonas Bonn l.lwz r3,PT_PC(r1) ;\ 1069d02a428SJonas Bonn l.mtspr r0,r3,SPR_EPCR_BASE ;\ 1079d02a428SJonas Bonn l.lwz r3,PT_SR(r1) ;\ 1089d02a428SJonas Bonn l.mtspr r0,r3,SPR_ESR_BASE ;\ 10963d7f9f1SStafford Horne l.lwz r3,PT_FPCSR(r1) ;\ 11063d7f9f1SStafford Horne l.mtspr r0,r3,SPR_FPCSR ;\ 1119d02a428SJonas Bonn l.lwz r2,PT_GPR2(r1) ;\ 1129d02a428SJonas Bonn l.lwz r3,PT_GPR3(r1) ;\ 1139d02a428SJonas Bonn l.lwz r4,PT_GPR4(r1) ;\ 1149d02a428SJonas Bonn l.lwz r5,PT_GPR5(r1) ;\ 1159d02a428SJonas Bonn l.lwz r6,PT_GPR6(r1) ;\ 1169d02a428SJonas Bonn l.lwz r7,PT_GPR7(r1) ;\ 1179d02a428SJonas Bonn l.lwz r8,PT_GPR8(r1) ;\ 1189d02a428SJonas Bonn l.lwz r9,PT_GPR9(r1) ;\ 1199d02a428SJonas Bonn l.lwz r10,PT_GPR10(r1) ;\ 1209d02a428SJonas Bonn l.lwz r11,PT_GPR11(r1) ;\ 1219d02a428SJonas Bonn l.lwz r12,PT_GPR12(r1) ;\ 1229d02a428SJonas Bonn l.lwz r13,PT_GPR13(r1) ;\ 1239d02a428SJonas Bonn l.lwz r14,PT_GPR14(r1) ;\ 1249d02a428SJonas Bonn l.lwz r15,PT_GPR15(r1) ;\ 1259d02a428SJonas Bonn l.lwz r16,PT_GPR16(r1) ;\ 1269d02a428SJonas Bonn l.lwz r17,PT_GPR17(r1) ;\ 1279d02a428SJonas Bonn l.lwz r18,PT_GPR18(r1) ;\ 1289d02a428SJonas Bonn l.lwz r19,PT_GPR19(r1) ;\ 1299d02a428SJonas Bonn l.lwz r20,PT_GPR20(r1) ;\ 1309d02a428SJonas Bonn l.lwz r21,PT_GPR21(r1) ;\ 1319d02a428SJonas Bonn l.lwz r22,PT_GPR22(r1) ;\ 1329d02a428SJonas Bonn l.lwz r23,PT_GPR23(r1) ;\ 1339d02a428SJonas Bonn l.lwz r24,PT_GPR24(r1) ;\ 1349d02a428SJonas Bonn l.lwz r25,PT_GPR25(r1) ;\ 1359d02a428SJonas Bonn l.lwz r26,PT_GPR26(r1) ;\ 1369d02a428SJonas Bonn l.lwz r27,PT_GPR27(r1) ;\ 1379d02a428SJonas Bonn l.lwz r28,PT_GPR28(r1) ;\ 1389d02a428SJonas Bonn l.lwz r29,PT_GPR29(r1) ;\ 1399d02a428SJonas Bonn l.lwz r30,PT_GPR30(r1) ;\ 1409d02a428SJonas Bonn l.lwz r31,PT_GPR31(r1) ;\ 1419d02a428SJonas Bonn l.lwz r1,PT_SP(r1) ;\ 1429d02a428SJonas Bonn l.rfe 1439d02a428SJonas Bonn 1449d02a428SJonas Bonn 1459d02a428SJonas Bonn#define EXCEPTION_ENTRY(handler) \ 1469d02a428SJonas Bonn .global handler ;\ 1479d02a428SJonas Bonnhandler: ;\ 1489d02a428SJonas Bonn /* r1, EPCR, ESR a already saved */ ;\ 1499d02a428SJonas Bonn l.sw PT_GPR2(r1),r2 ;\ 1509d02a428SJonas Bonn l.sw PT_GPR3(r1),r3 ;\ 1519d02a428SJonas Bonn /* r4 already save */ ;\ 1529d02a428SJonas Bonn l.sw PT_GPR5(r1),r5 ;\ 1539d02a428SJonas Bonn l.sw PT_GPR6(r1),r6 ;\ 1549d02a428SJonas Bonn l.sw PT_GPR7(r1),r7 ;\ 1559d02a428SJonas Bonn l.sw PT_GPR8(r1),r8 ;\ 1569d02a428SJonas Bonn l.sw PT_GPR9(r1),r9 ;\ 1579d02a428SJonas Bonn /* r10 already saved */ ;\ 1589d02a428SJonas Bonn l.sw PT_GPR11(r1),r11 ;\ 1599d02a428SJonas Bonn /* r12 already saved */ ;\ 1609d02a428SJonas Bonn l.sw PT_GPR13(r1),r13 ;\ 1619d02a428SJonas Bonn l.sw PT_GPR14(r1),r14 ;\ 1629d02a428SJonas Bonn l.sw PT_GPR15(r1),r15 ;\ 1639d02a428SJonas Bonn l.sw PT_GPR16(r1),r16 ;\ 1649d02a428SJonas Bonn l.sw PT_GPR17(r1),r17 ;\ 1659d02a428SJonas Bonn l.sw PT_GPR18(r1),r18 ;\ 1669d02a428SJonas Bonn l.sw PT_GPR19(r1),r19 ;\ 1679d02a428SJonas Bonn l.sw PT_GPR20(r1),r20 ;\ 1689d02a428SJonas Bonn l.sw PT_GPR21(r1),r21 ;\ 1699d02a428SJonas Bonn l.sw PT_GPR22(r1),r22 ;\ 1709d02a428SJonas Bonn l.sw PT_GPR23(r1),r23 ;\ 1719d02a428SJonas Bonn l.sw PT_GPR24(r1),r24 ;\ 1729d02a428SJonas Bonn l.sw PT_GPR25(r1),r25 ;\ 1739d02a428SJonas Bonn l.sw PT_GPR26(r1),r26 ;\ 1749d02a428SJonas Bonn l.sw PT_GPR27(r1),r27 ;\ 1759d02a428SJonas Bonn l.sw PT_GPR28(r1),r28 ;\ 1769d02a428SJonas Bonn l.sw PT_GPR29(r1),r29 ;\ 1779d02a428SJonas Bonn /* r30 already save */ ;\ 1789d02a428SJonas Bonn l.sw PT_GPR31(r1),r31 ;\ 17978cdfb5cSStafford Horne TRACE_IRQS_OFF_ENTRY ;\ 18063d7f9f1SStafford Horne l.mfspr r30,r0,SPR_FPCSR ;\ 18163d7f9f1SStafford Horne l.sw PT_FPCSR(r1),r30 ;\ 1826cbe5e95SJonas Bonn /* Store -1 in orig_gpr11 for non-syscall exceptions */ ;\ 1836cbe5e95SJonas Bonn l.addi r30,r0,-1 ;\ 1846cbe5e95SJonas Bonn l.sw PT_ORIG_GPR11(r1),r30 1859d02a428SJonas Bonn 1869d02a428SJonas Bonn#define UNHANDLED_EXCEPTION(handler,vector) \ 1879d02a428SJonas Bonn .global handler ;\ 1889d02a428SJonas Bonnhandler: ;\ 1899d02a428SJonas Bonn /* r1, EPCR, ESR already saved */ ;\ 1909d02a428SJonas Bonn l.sw PT_GPR2(r1),r2 ;\ 1919d02a428SJonas Bonn l.sw PT_GPR3(r1),r3 ;\ 1929d02a428SJonas Bonn l.sw PT_GPR5(r1),r5 ;\ 1939d02a428SJonas Bonn l.sw PT_GPR6(r1),r6 ;\ 1949d02a428SJonas Bonn l.sw PT_GPR7(r1),r7 ;\ 1959d02a428SJonas Bonn l.sw PT_GPR8(r1),r8 ;\ 1969d02a428SJonas Bonn l.sw PT_GPR9(r1),r9 ;\ 1979d02a428SJonas Bonn /* r10 already saved */ ;\ 1989d02a428SJonas Bonn l.sw PT_GPR11(r1),r11 ;\ 1999d02a428SJonas Bonn /* r12 already saved */ ;\ 2009d02a428SJonas Bonn l.sw PT_GPR13(r1),r13 ;\ 2019d02a428SJonas Bonn l.sw PT_GPR14(r1),r14 ;\ 2029d02a428SJonas Bonn l.sw PT_GPR15(r1),r15 ;\ 2039d02a428SJonas Bonn l.sw PT_GPR16(r1),r16 ;\ 2049d02a428SJonas Bonn l.sw PT_GPR17(r1),r17 ;\ 2059d02a428SJonas Bonn l.sw PT_GPR18(r1),r18 ;\ 2069d02a428SJonas Bonn l.sw PT_GPR19(r1),r19 ;\ 2079d02a428SJonas Bonn l.sw PT_GPR20(r1),r20 ;\ 2089d02a428SJonas Bonn l.sw PT_GPR21(r1),r21 ;\ 2099d02a428SJonas Bonn l.sw PT_GPR22(r1),r22 ;\ 2109d02a428SJonas Bonn l.sw PT_GPR23(r1),r23 ;\ 2119d02a428SJonas Bonn l.sw PT_GPR24(r1),r24 ;\ 2129d02a428SJonas Bonn l.sw PT_GPR25(r1),r25 ;\ 2139d02a428SJonas Bonn l.sw PT_GPR26(r1),r26 ;\ 2149d02a428SJonas Bonn l.sw PT_GPR27(r1),r27 ;\ 2159d02a428SJonas Bonn l.sw PT_GPR28(r1),r28 ;\ 2169d02a428SJonas Bonn l.sw PT_GPR29(r1),r29 ;\ 217812489acSStafford Horne /* r30 already saved */ ;\ 218812489acSStafford Horne l.sw PT_GPR31(r1),r31 ;\ 2196cbe5e95SJonas Bonn /* Store -1 in orig_gpr11 for non-syscall exceptions */ ;\ 2206cbe5e95SJonas Bonn l.addi r30,r0,-1 ;\ 2216cbe5e95SJonas Bonn l.sw PT_ORIG_GPR11(r1),r30 ;\ 22263d7f9f1SStafford Horne l.mfspr r30,r0,SPR_FPCSR ;\ 22363d7f9f1SStafford Horne l.sw PT_FPCSR(r1),r30 ;\ 2249d02a428SJonas Bonn l.addi r3,r1,0 ;\ 2259d02a428SJonas Bonn /* r4 is exception EA */ ;\ 2269d02a428SJonas Bonn l.addi r5,r0,vector ;\ 2279d02a428SJonas Bonn l.jal unhandled_exception ;\ 2289d02a428SJonas Bonn l.nop ;\ 2299d02a428SJonas Bonn l.j _ret_from_exception ;\ 2309d02a428SJonas Bonn l.nop 2319d02a428SJonas Bonn 23263104c06SStefan Kristiansson/* clobbers 'reg' */ 23363104c06SStefan Kristiansson#define CLEAR_LWA_FLAG(reg) \ 23463104c06SStefan Kristiansson l.movhi reg,hi(lwa_flag) ;\ 23563104c06SStefan Kristiansson l.ori reg,reg,lo(lwa_flag) ;\ 23663104c06SStefan Kristiansson l.sw 0(reg),r0 2379d02a428SJonas Bonn/* 2389d02a428SJonas Bonn * NOTE: one should never assume that SPR_EPC, SPR_ESR, SPR_EEAR 2399d02a428SJonas Bonn * contain the same values as when exception we're handling 2409d02a428SJonas Bonn * occured. in fact they never do. if you need them use 2419d02a428SJonas Bonn * values saved on stack (for SPR_EPC, SPR_ESR) or content 2429d02a428SJonas Bonn * of r4 (for SPR_EEAR). for details look at EXCEPTION_HANDLE() 24357ce8ba0SGeert Uytterhoeven * in 'arch/openrisc/kernel/head.S' 2449d02a428SJonas Bonn */ 2459d02a428SJonas Bonn 2469d02a428SJonas Bonn/* =====================================================[ exceptions] === */ 2479d02a428SJonas Bonn 2489d02a428SJonas Bonn/* ---[ 0x100: RESET exception ]----------------------------------------- */ 2499d02a428SJonas Bonn 2509d02a428SJonas BonnEXCEPTION_ENTRY(_tng_kernel_start) 2519d02a428SJonas Bonn l.jal _start 2529d02a428SJonas Bonn l.andi r0,r0,0 2539d02a428SJonas Bonn 2549d02a428SJonas Bonn/* ---[ 0x200: BUS exception ]------------------------------------------- */ 2559d02a428SJonas Bonn 2569d02a428SJonas BonnEXCEPTION_ENTRY(_bus_fault_handler) 25763104c06SStefan Kristiansson CLEAR_LWA_FLAG(r3) 2589d02a428SJonas Bonn /* r4: EA of fault (set by EXCEPTION_HANDLE) */ 2599d02a428SJonas Bonn l.jal do_bus_fault 2609d02a428SJonas Bonn l.addi r3,r1,0 /* pt_regs */ 2619d02a428SJonas Bonn 2629d02a428SJonas Bonn l.j _ret_from_exception 2639d02a428SJonas Bonn l.nop 2649d02a428SJonas Bonn 2659d02a428SJonas Bonn/* ---[ 0x300: Data Page Fault exception ]------------------------------- */ 266a81252d7SJonas BonnEXCEPTION_ENTRY(_dtlb_miss_page_fault_handler) 26763104c06SStefan Kristiansson CLEAR_LWA_FLAG(r3) 268a81252d7SJonas Bonn l.and r5,r5,r0 269a81252d7SJonas Bonn l.j 1f 270a81252d7SJonas Bonn l.nop 2719d02a428SJonas Bonn 2729d02a428SJonas BonnEXCEPTION_ENTRY(_data_page_fault_handler) 27363104c06SStefan Kristiansson CLEAR_LWA_FLAG(r3) 2749d02a428SJonas Bonn /* set up parameters for do_page_fault */ 275a81252d7SJonas Bonn l.ori r5,r0,0x300 // exception vector 276a81252d7SJonas Bonn1: 2779d02a428SJonas Bonn l.addi r3,r1,0 // pt_regs 2789d02a428SJonas Bonn /* r4 set be EXCEPTION_HANDLE */ // effective address of fault 2799d02a428SJonas Bonn 2809d02a428SJonas Bonn#ifdef CONFIG_OPENRISC_NO_SPR_SR_DSX 2819d02a428SJonas Bonn l.lwz r6,PT_PC(r3) // address of an offending insn 2829d02a428SJonas Bonn l.lwz r6,0(r6) // instruction that caused pf 2839d02a428SJonas Bonn 2849d02a428SJonas Bonn l.srli r6,r6,26 // check opcode for jump insn 2859d02a428SJonas Bonn l.sfeqi r6,0 // l.j 2869d02a428SJonas Bonn l.bf 8f 2879d02a428SJonas Bonn l.sfeqi r6,1 // l.jal 2889d02a428SJonas Bonn l.bf 8f 2899d02a428SJonas Bonn l.sfeqi r6,3 // l.bnf 2909d02a428SJonas Bonn l.bf 8f 2919d02a428SJonas Bonn l.sfeqi r6,4 // l.bf 2929d02a428SJonas Bonn l.bf 8f 2939d02a428SJonas Bonn l.sfeqi r6,0x11 // l.jr 2949d02a428SJonas Bonn l.bf 8f 2959d02a428SJonas Bonn l.sfeqi r6,0x12 // l.jalr 2969d02a428SJonas Bonn l.bf 8f 2979d02a428SJonas Bonn l.nop 2989d02a428SJonas Bonn 2999d02a428SJonas Bonn l.j 9f 3009d02a428SJonas Bonn l.nop 3019d02a428SJonas Bonn 3022ead7abaSStafford Horne8: // offending insn is in delay slot 3039d02a428SJonas Bonn l.lwz r6,PT_PC(r3) // address of an offending insn 3049d02a428SJonas Bonn l.addi r6,r6,4 3059d02a428SJonas Bonn l.lwz r6,0(r6) // instruction that caused pf 3069d02a428SJonas Bonn l.srli r6,r6,26 // get opcode 3072ead7abaSStafford Horne9: // offending instruction opcode loaded in r6 3089d02a428SJonas Bonn 3099d02a428SJonas Bonn#else 3109d02a428SJonas Bonn 311ae15a41aSStafford Horne l.mfspr r6,r0,SPR_SR // SR 3129d02a428SJonas Bonn l.andi r6,r6,SPR_SR_DSX // check for delay slot exception 313e6d20c55SStafford Horne l.sfne r6,r0 // exception happened in delay slot 3149d02a428SJonas Bonn l.bnf 7f 3159d02a428SJonas Bonn l.lwz r6,PT_PC(r3) // address of an offending insn 3169d02a428SJonas Bonn 3179d02a428SJonas Bonn l.addi r6,r6,4 // offending insn is in delay slot 3189d02a428SJonas Bonn7: 3199d02a428SJonas Bonn l.lwz r6,0(r6) // instruction that caused pf 3209d02a428SJonas Bonn l.srli r6,r6,26 // check opcode for write access 3219d02a428SJonas Bonn#endif 3229d02a428SJonas Bonn 323cdb75442SStefan Kristiansson l.sfgeui r6,0x33 // check opcode for write access 3249d02a428SJonas Bonn l.bnf 1f 3259d02a428SJonas Bonn l.sfleui r6,0x37 3269d02a428SJonas Bonn l.bnf 1f 3279d02a428SJonas Bonn l.ori r6,r0,0x1 // write access 3289d02a428SJonas Bonn l.j 2f 3299d02a428SJonas Bonn l.nop 3309d02a428SJonas Bonn1: l.ori r6,r0,0x0 // !write access 3319d02a428SJonas Bonn2: 3329d02a428SJonas Bonn 33311648cbbSRandy Dunlap /* call fault.c handler in openrisc/mm/fault.c */ 3349d02a428SJonas Bonn l.jal do_page_fault 3359d02a428SJonas Bonn l.nop 3369d02a428SJonas Bonn l.j _ret_from_exception 3379d02a428SJonas Bonn l.nop 3389d02a428SJonas Bonn 3399d02a428SJonas Bonn/* ---[ 0x400: Insn Page Fault exception ]------------------------------- */ 340a81252d7SJonas BonnEXCEPTION_ENTRY(_itlb_miss_page_fault_handler) 34163104c06SStefan Kristiansson CLEAR_LWA_FLAG(r3) 342a81252d7SJonas Bonn l.and r5,r5,r0 343a81252d7SJonas Bonn l.j 1f 344a81252d7SJonas Bonn l.nop 3459d02a428SJonas Bonn 3469d02a428SJonas BonnEXCEPTION_ENTRY(_insn_page_fault_handler) 34763104c06SStefan Kristiansson CLEAR_LWA_FLAG(r3) 3489d02a428SJonas Bonn /* set up parameters for do_page_fault */ 349a81252d7SJonas Bonn l.ori r5,r0,0x400 // exception vector 350a81252d7SJonas Bonn1: 3519d02a428SJonas Bonn l.addi r3,r1,0 // pt_regs 3529d02a428SJonas Bonn /* r4 set be EXCEPTION_HANDLE */ // effective address of fault 3539d02a428SJonas Bonn l.ori r6,r0,0x0 // !write access 3549d02a428SJonas Bonn 35511648cbbSRandy Dunlap /* call fault.c handler in openrisc/mm/fault.c */ 3569d02a428SJonas Bonn l.jal do_page_fault 3579d02a428SJonas Bonn l.nop 3589d02a428SJonas Bonn l.j _ret_from_exception 3599d02a428SJonas Bonn l.nop 3609d02a428SJonas Bonn 3619d02a428SJonas Bonn 3629d02a428SJonas Bonn/* ---[ 0x500: Timer exception ]----------------------------------------- */ 3639d02a428SJonas Bonn 3649d02a428SJonas BonnEXCEPTION_ENTRY(_timer_handler) 36563104c06SStefan Kristiansson CLEAR_LWA_FLAG(r3) 3669d02a428SJonas Bonn l.jal timer_interrupt 3679d02a428SJonas Bonn l.addi r3,r1,0 /* pt_regs */ 3689d02a428SJonas Bonn 3699d02a428SJonas Bonn l.j _ret_from_intr 3709d02a428SJonas Bonn l.nop 3719d02a428SJonas Bonn 372550116d2SMasahiro Yamada/* ---[ 0x600: Alignment exception ]-------------------------------------- */ 3739d02a428SJonas Bonn 3749d02a428SJonas BonnEXCEPTION_ENTRY(_alignment_handler) 37563104c06SStefan Kristiansson CLEAR_LWA_FLAG(r3) 3769d02a428SJonas Bonn /* r4: EA of fault (set by EXCEPTION_HANDLE) */ 3779d02a428SJonas Bonn l.jal do_unaligned_access 3789d02a428SJonas Bonn l.addi r3,r1,0 /* pt_regs */ 3799d02a428SJonas Bonn 3809d02a428SJonas Bonn l.j _ret_from_exception 3819d02a428SJonas Bonn l.nop 3829d02a428SJonas Bonn 3839d02a428SJonas Bonn#if 0 384550116d2SMasahiro YamadaEXCEPTION_ENTRY(_alignment_handler) 3854e0385ddSMasahiro Yamada// l.mfspr r2,r0,SPR_EEAR_BASE /* Load the effective address */ 3869d02a428SJonas Bonn l.addi r2,r4,0 3879d02a428SJonas Bonn// l.mfspr r5,r0,SPR_EPCR_BASE /* Load the insn address */ 3889d02a428SJonas Bonn l.lwz r5,PT_PC(r1) 3899d02a428SJonas Bonn 3909d02a428SJonas Bonn l.lwz r3,0(r5) /* Load insn */ 3919d02a428SJonas Bonn l.srli r4,r3,26 /* Shift left to get the insn opcode */ 3929d02a428SJonas Bonn 3939d02a428SJonas Bonn l.sfeqi r4,0x00 /* Check if the load/store insn is in delay slot */ 3949d02a428SJonas Bonn l.bf jmp 3959d02a428SJonas Bonn l.sfeqi r4,0x01 3969d02a428SJonas Bonn l.bf jmp 3979d02a428SJonas Bonn l.sfeqi r4,0x03 3989d02a428SJonas Bonn l.bf jmp 3999d02a428SJonas Bonn l.sfeqi r4,0x04 4009d02a428SJonas Bonn l.bf jmp 4019d02a428SJonas Bonn l.sfeqi r4,0x11 4029d02a428SJonas Bonn l.bf jr 4039d02a428SJonas Bonn l.sfeqi r4,0x12 4049d02a428SJonas Bonn l.bf jr 4059d02a428SJonas Bonn l.nop 4069d02a428SJonas Bonn l.j 1f 4079d02a428SJonas Bonn l.addi r5,r5,4 /* Increment PC to get return insn address */ 4089d02a428SJonas Bonn 4099d02a428SJonas Bonnjmp: 4109d02a428SJonas Bonn l.slli r4,r3,6 /* Get the signed extended jump length */ 4119d02a428SJonas Bonn l.srai r4,r4,4 4129d02a428SJonas Bonn 4139d02a428SJonas Bonn l.lwz r3,4(r5) /* Load the real load/store insn */ 4149d02a428SJonas Bonn 4159d02a428SJonas Bonn l.add r5,r5,r4 /* Calculate jump target address */ 4169d02a428SJonas Bonn 4179d02a428SJonas Bonn l.j 1f 4189d02a428SJonas Bonn l.srli r4,r3,26 /* Shift left to get the insn opcode */ 4199d02a428SJonas Bonn 4209d02a428SJonas Bonnjr: 4219d02a428SJonas Bonn l.slli r4,r3,9 /* Shift to get the reg nb */ 4229d02a428SJonas Bonn l.andi r4,r4,0x7c 4239d02a428SJonas Bonn 4249d02a428SJonas Bonn l.lwz r3,4(r5) /* Load the real load/store insn */ 4259d02a428SJonas Bonn 4269d02a428SJonas Bonn l.add r4,r4,r1 /* Load the jump register value from the stack */ 4279d02a428SJonas Bonn l.lwz r5,0(r4) 4289d02a428SJonas Bonn 4299d02a428SJonas Bonn l.srli r4,r3,26 /* Shift left to get the insn opcode */ 4309d02a428SJonas Bonn 4319d02a428SJonas Bonn 4329d02a428SJonas Bonn1: 4339d02a428SJonas Bonn// l.mtspr r0,r5,SPR_EPCR_BASE 4349d02a428SJonas Bonn l.sw PT_PC(r1),r5 4359d02a428SJonas Bonn 4369d02a428SJonas Bonn l.sfeqi r4,0x26 4379d02a428SJonas Bonn l.bf lhs 4389d02a428SJonas Bonn l.sfeqi r4,0x25 4399d02a428SJonas Bonn l.bf lhz 4409d02a428SJonas Bonn l.sfeqi r4,0x22 4419d02a428SJonas Bonn l.bf lws 4429d02a428SJonas Bonn l.sfeqi r4,0x21 4439d02a428SJonas Bonn l.bf lwz 4449d02a428SJonas Bonn l.sfeqi r4,0x37 4459d02a428SJonas Bonn l.bf sh 4469d02a428SJonas Bonn l.sfeqi r4,0x35 4479d02a428SJonas Bonn l.bf sw 4489d02a428SJonas Bonn l.nop 4499d02a428SJonas Bonn 4509d02a428SJonas Bonn1: l.j 1b /* I don't know what to do */ 4519d02a428SJonas Bonn l.nop 4529d02a428SJonas Bonn 4539d02a428SJonas Bonnlhs: l.lbs r5,0(r2) 4549d02a428SJonas Bonn l.slli r5,r5,8 4559d02a428SJonas Bonn l.lbz r6,1(r2) 4569d02a428SJonas Bonn l.or r5,r5,r6 4579d02a428SJonas Bonn l.srli r4,r3,19 4589d02a428SJonas Bonn l.andi r4,r4,0x7c 4599d02a428SJonas Bonn l.add r4,r4,r1 4609d02a428SJonas Bonn l.j align_end 4619d02a428SJonas Bonn l.sw 0(r4),r5 4629d02a428SJonas Bonn 4639d02a428SJonas Bonnlhz: l.lbz r5,0(r2) 4649d02a428SJonas Bonn l.slli r5,r5,8 4659d02a428SJonas Bonn l.lbz r6,1(r2) 4669d02a428SJonas Bonn l.or r5,r5,r6 4679d02a428SJonas Bonn l.srli r4,r3,19 4689d02a428SJonas Bonn l.andi r4,r4,0x7c 4699d02a428SJonas Bonn l.add r4,r4,r1 4709d02a428SJonas Bonn l.j align_end 4719d02a428SJonas Bonn l.sw 0(r4),r5 4729d02a428SJonas Bonn 4739d02a428SJonas Bonnlws: l.lbs r5,0(r2) 4749d02a428SJonas Bonn l.slli r5,r5,24 4759d02a428SJonas Bonn l.lbz r6,1(r2) 4769d02a428SJonas Bonn l.slli r6,r6,16 4779d02a428SJonas Bonn l.or r5,r5,r6 4789d02a428SJonas Bonn l.lbz r6,2(r2) 4799d02a428SJonas Bonn l.slli r6,r6,8 4809d02a428SJonas Bonn l.or r5,r5,r6 4819d02a428SJonas Bonn l.lbz r6,3(r2) 4829d02a428SJonas Bonn l.or r5,r5,r6 4839d02a428SJonas Bonn l.srli r4,r3,19 4849d02a428SJonas Bonn l.andi r4,r4,0x7c 4859d02a428SJonas Bonn l.add r4,r4,r1 4869d02a428SJonas Bonn l.j align_end 4879d02a428SJonas Bonn l.sw 0(r4),r5 4889d02a428SJonas Bonn 4899d02a428SJonas Bonnlwz: l.lbz r5,0(r2) 4909d02a428SJonas Bonn l.slli r5,r5,24 4919d02a428SJonas Bonn l.lbz r6,1(r2) 4929d02a428SJonas Bonn l.slli r6,r6,16 4939d02a428SJonas Bonn l.or r5,r5,r6 4949d02a428SJonas Bonn l.lbz r6,2(r2) 4959d02a428SJonas Bonn l.slli r6,r6,8 4969d02a428SJonas Bonn l.or r5,r5,r6 4979d02a428SJonas Bonn l.lbz r6,3(r2) 4989d02a428SJonas Bonn l.or r5,r5,r6 4999d02a428SJonas Bonn l.srli r4,r3,19 5009d02a428SJonas Bonn l.andi r4,r4,0x7c 5019d02a428SJonas Bonn l.add r4,r4,r1 5029d02a428SJonas Bonn l.j align_end 5039d02a428SJonas Bonn l.sw 0(r4),r5 5049d02a428SJonas Bonn 5059d02a428SJonas Bonnsh: 5069d02a428SJonas Bonn l.srli r4,r3,9 5079d02a428SJonas Bonn l.andi r4,r4,0x7c 5089d02a428SJonas Bonn l.add r4,r4,r1 5099d02a428SJonas Bonn l.lwz r5,0(r4) 5109d02a428SJonas Bonn l.sb 1(r2),r5 5119d02a428SJonas Bonn l.srli r5,r5,8 5129d02a428SJonas Bonn l.j align_end 5139d02a428SJonas Bonn l.sb 0(r2),r5 5149d02a428SJonas Bonn 5159d02a428SJonas Bonnsw: 5169d02a428SJonas Bonn l.srli r4,r3,9 5179d02a428SJonas Bonn l.andi r4,r4,0x7c 5189d02a428SJonas Bonn l.add r4,r4,r1 5199d02a428SJonas Bonn l.lwz r5,0(r4) 5209d02a428SJonas Bonn l.sb 3(r2),r5 5219d02a428SJonas Bonn l.srli r5,r5,8 5229d02a428SJonas Bonn l.sb 2(r2),r5 5239d02a428SJonas Bonn l.srli r5,r5,8 5249d02a428SJonas Bonn l.sb 1(r2),r5 5259d02a428SJonas Bonn l.srli r5,r5,8 5269d02a428SJonas Bonn l.j align_end 5279d02a428SJonas Bonn l.sb 0(r2),r5 5289d02a428SJonas Bonn 5299d02a428SJonas Bonnalign_end: 5309d02a428SJonas Bonn l.j _ret_from_intr 5319d02a428SJonas Bonn l.nop 5329d02a428SJonas Bonn#endif 5339d02a428SJonas Bonn 5349d02a428SJonas Bonn/* ---[ 0x700: Illegal insn exception ]---------------------------------- */ 5359d02a428SJonas Bonn 5369d02a428SJonas BonnEXCEPTION_ENTRY(_illegal_instruction_handler) 5379d02a428SJonas Bonn /* r4: EA of fault (set by EXCEPTION_HANDLE) */ 5389d02a428SJonas Bonn l.jal do_illegal_instruction 5399d02a428SJonas Bonn l.addi r3,r1,0 /* pt_regs */ 5409d02a428SJonas Bonn 5419d02a428SJonas Bonn l.j _ret_from_exception 5429d02a428SJonas Bonn l.nop 5439d02a428SJonas Bonn 5449d02a428SJonas Bonn/* ---[ 0x800: External interrupt exception ]---------------------------- */ 5459d02a428SJonas Bonn 5469d02a428SJonas BonnEXCEPTION_ENTRY(_external_irq_handler) 5479d02a428SJonas Bonn#ifdef CONFIG_OPENRISC_ESR_EXCEPTION_BUG_CHECK 5489d02a428SJonas Bonn l.lwz r4,PT_SR(r1) // were interrupts enabled ? 5499d02a428SJonas Bonn l.andi r4,r4,SPR_SR_IEE 5509d02a428SJonas Bonn l.sfeqi r4,0 5519d02a428SJonas Bonn l.bnf 1f // ext irq enabled, all ok. 5529d02a428SJonas Bonn l.nop 5539d02a428SJonas Bonn 554946e1052SRandy Dunlap#ifdef CONFIG_PRINTK 5559d02a428SJonas Bonn l.addi r1,r1,-0x8 5569d02a428SJonas Bonn l.movhi r3,hi(42f) 5579d02a428SJonas Bonn l.ori r3,r3,lo(42f) 5589d02a428SJonas Bonn l.sw 0x0(r1),r3 55933701557SChris Down l.jal _printk 5609d02a428SJonas Bonn l.sw 0x4(r1),r4 5619d02a428SJonas Bonn l.addi r1,r1,0x8 5629d02a428SJonas Bonn 5639d02a428SJonas Bonn .section .rodata, "a" 5649d02a428SJonas Bonn42: 5659d02a428SJonas Bonn .string "\n\rESR interrupt bug: in _external_irq_handler (ESR %x)\n\r" 5669d02a428SJonas Bonn .align 4 5679d02a428SJonas Bonn .previous 568946e1052SRandy Dunlap#endif 5699d02a428SJonas Bonn 5709d02a428SJonas Bonn l.ori r4,r4,SPR_SR_IEE // fix the bug 5719d02a428SJonas Bonn// l.sw PT_SR(r1),r4 5729d02a428SJonas Bonn1: 5739d02a428SJonas Bonn#endif 57463104c06SStefan Kristiansson CLEAR_LWA_FLAG(r3) 5759d02a428SJonas Bonn l.addi r3,r1,0 576418360b2SMark Rutland l.movhi r8,hi(generic_handle_arch_irq) 577418360b2SMark Rutland l.ori r8,r8,lo(generic_handle_arch_irq) 5789d02a428SJonas Bonn l.jalr r8 5799d02a428SJonas Bonn l.nop 5809d02a428SJonas Bonn l.j _ret_from_intr 5819d02a428SJonas Bonn l.nop 5829d02a428SJonas Bonn 5839d02a428SJonas Bonn/* ---[ 0x900: DTLB miss exception ]------------------------------------- */ 5849d02a428SJonas Bonn 5859d02a428SJonas Bonn 5869d02a428SJonas Bonn/* ---[ 0xa00: ITLB miss exception ]------------------------------------- */ 5879d02a428SJonas Bonn 5889d02a428SJonas Bonn 5899d02a428SJonas Bonn/* ---[ 0xb00: Range exception ]----------------------------------------- */ 5909d02a428SJonas Bonn 5919d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0xb00,0xb00) 5929d02a428SJonas Bonn 5939d02a428SJonas Bonn/* ---[ 0xc00: Syscall exception ]--------------------------------------- */ 5949d02a428SJonas Bonn 5959d02a428SJonas Bonn/* 5969d02a428SJonas Bonn * Syscalls are a special type of exception in that they are 5979d02a428SJonas Bonn * _explicitly_ invoked by userspace and can therefore be 5989d02a428SJonas Bonn * held to conform to the same ABI as normal functions with 5999d02a428SJonas Bonn * respect to whether registers are preserved across the call 6009d02a428SJonas Bonn * or not. 6019d02a428SJonas Bonn */ 6029d02a428SJonas Bonn 6039d02a428SJonas Bonn/* Upon syscall entry we just save the callee-saved registers 6049d02a428SJonas Bonn * and not the call-clobbered ones. 6059d02a428SJonas Bonn */ 6069d02a428SJonas Bonn 6079d02a428SJonas Bonn_string_syscall_return: 608a0a94bc9SStafford Horne .string "syscall r9:0x%08x -> syscall(%ld) return %ld\0" 6099d02a428SJonas Bonn .align 4 6109d02a428SJonas Bonn 6119d02a428SJonas BonnENTRY(_sys_call_handler) 6129d02a428SJonas Bonn /* r1, EPCR, ESR a already saved */ 6139d02a428SJonas Bonn l.sw PT_GPR2(r1),r2 6149d02a428SJonas Bonn /* r3-r8 must be saved because syscall restart relies 6159d02a428SJonas Bonn * on us being able to restart the syscall args... technically 6169d02a428SJonas Bonn * they should be clobbered, otherwise 6179d02a428SJonas Bonn */ 6189d02a428SJonas Bonn l.sw PT_GPR3(r1),r3 61963104c06SStefan Kristiansson /* 62063104c06SStefan Kristiansson * r4 already saved 62163104c06SStefan Kristiansson * r4 holds the EEAR address of the fault, use it as screatch reg and 62263104c06SStefan Kristiansson * then load the original r4 62363104c06SStefan Kristiansson */ 62463104c06SStefan Kristiansson CLEAR_LWA_FLAG(r4) 6259d02a428SJonas Bonn l.lwz r4,PT_GPR4(r1) 6269d02a428SJonas Bonn l.sw PT_GPR5(r1),r5 6279d02a428SJonas Bonn l.sw PT_GPR6(r1),r6 6289d02a428SJonas Bonn l.sw PT_GPR7(r1),r7 6299d02a428SJonas Bonn l.sw PT_GPR8(r1),r8 6309d02a428SJonas Bonn l.sw PT_GPR9(r1),r9 6319d02a428SJonas Bonn /* r10 already saved */ 6329d02a428SJonas Bonn l.sw PT_GPR11(r1),r11 6336cbe5e95SJonas Bonn /* orig_gpr11 must be set for syscalls */ 6349d02a428SJonas Bonn l.sw PT_ORIG_GPR11(r1),r11 6359d02a428SJonas Bonn /* r12,r13 already saved */ 6369d02a428SJonas Bonn 6379d02a428SJonas Bonn /* r14-r28 (even) aren't touched by the syscall fast path below 6389d02a428SJonas Bonn * so we don't need to save them. However, the functions that return 6399d02a428SJonas Bonn * to userspace via a call to switch() DO need to save these because 6409d02a428SJonas Bonn * switch() effectively clobbers them... saving these registers for 6419d02a428SJonas Bonn * such functions is handled in their syscall wrappers (see fork, vfork, 6429d02a428SJonas Bonn * and clone, below). 6439d02a428SJonas Bonn 6449d02a428SJonas Bonn /* r30 is the only register we clobber in the fast path */ 6459d02a428SJonas Bonn /* r30 already saved */ 6469d02a428SJonas Bonn/* l.sw PT_GPR30(r1),r30 */ 6479d02a428SJonas Bonn 6489d02a428SJonas Bonn_syscall_check_trace_enter: 64978cdfb5cSStafford Horne /* syscalls run with interrupts enabled */ 65078cdfb5cSStafford Horne TRACE_IRQS_ON_SYSCALL 65178cdfb5cSStafford Horne ENABLE_INTERRUPTS(r29) // enable interrupts, r29 is temp 65278cdfb5cSStafford Horne 6539d02a428SJonas Bonn /* If TIF_SYSCALL_TRACE is set, then we want to do syscall tracing */ 6549d02a428SJonas Bonn l.lwz r30,TI_FLAGS(r10) 6559d02a428SJonas Bonn l.andi r30,r30,_TIF_SYSCALL_TRACE 6569d02a428SJonas Bonn l.sfne r30,r0 6579d02a428SJonas Bonn l.bf _syscall_trace_enter 6589d02a428SJonas Bonn l.nop 6599d02a428SJonas Bonn 6609d02a428SJonas Bonn_syscall_check: 6619d02a428SJonas Bonn /* Ensure that the syscall number is reasonable */ 6629d02a428SJonas Bonn l.sfgeui r11,__NR_syscalls 6639d02a428SJonas Bonn l.bf _syscall_badsys 6649d02a428SJonas Bonn l.nop 6659d02a428SJonas Bonn 6669d02a428SJonas Bonn_syscall_call: 6679d02a428SJonas Bonn l.movhi r29,hi(sys_call_table) 6689d02a428SJonas Bonn l.ori r29,r29,lo(sys_call_table) 6699d02a428SJonas Bonn l.slli r11,r11,2 6709d02a428SJonas Bonn l.add r29,r29,r11 6719d02a428SJonas Bonn l.lwz r29,0(r29) 6729d02a428SJonas Bonn 6739d02a428SJonas Bonn l.jalr r29 6749d02a428SJonas Bonn l.nop 6759d02a428SJonas Bonn 6769d02a428SJonas Bonn_syscall_return: 6779d02a428SJonas Bonn /* All syscalls return here... just pay attention to ret_from_fork 6789d02a428SJonas Bonn * which does it in a round-about way. 6799d02a428SJonas Bonn */ 6809d02a428SJonas Bonn l.sw PT_GPR11(r1),r11 // save return value 6819d02a428SJonas Bonn 6829d02a428SJonas Bonn#if 0 6839d02a428SJonas Bonn_syscall_debug: 6849d02a428SJonas Bonn l.movhi r3,hi(_string_syscall_return) 6859d02a428SJonas Bonn l.ori r3,r3,lo(_string_syscall_return) 686a0a94bc9SStafford Horne l.ori r27,r0,2 6879d02a428SJonas Bonn l.sw -4(r1),r27 6889d02a428SJonas Bonn l.sw -8(r1),r11 689a0a94bc9SStafford Horne l.lwz r29,PT_ORIG_GPR11(r1) 690a0a94bc9SStafford Horne l.sw -12(r1),r29 691a0a94bc9SStafford Horne l.lwz r29,PT_GPR9(r1) 692a0a94bc9SStafford Horne l.sw -16(r1),r29 69333701557SChris Down l.movhi r27,hi(_printk) 69433701557SChris Down l.ori r27,r27,lo(_printk) 6959d02a428SJonas Bonn l.jalr r27 696a0a94bc9SStafford Horne l.addi r1,r1,-16 697a0a94bc9SStafford Horne l.addi r1,r1,16 698a0a94bc9SStafford Horne#endif 699a0a94bc9SStafford Horne#if 0 700a0a94bc9SStafford Horne_syscall_show_regs: 701a0a94bc9SStafford Horne l.movhi r27,hi(show_registers) 702a0a94bc9SStafford Horne l.ori r27,r27,lo(show_registers) 703a0a94bc9SStafford Horne l.jalr r27 704a0a94bc9SStafford Horne l.or r3,r1,r1 7059d02a428SJonas Bonn#endif 7069d02a428SJonas Bonn 7079d02a428SJonas Bonn_syscall_check_trace_leave: 7089d02a428SJonas Bonn /* r30 is a callee-saved register so this should still hold the 7099d02a428SJonas Bonn * _TIF_SYSCALL_TRACE flag from _syscall_check_trace_enter above... 7109d02a428SJonas Bonn * _syscall_trace_leave expects syscall result to be in pt_regs->r11. 7119d02a428SJonas Bonn */ 7129d02a428SJonas Bonn l.sfne r30,r0 7139d02a428SJonas Bonn l.bf _syscall_trace_leave 7149d02a428SJonas Bonn l.nop 7159d02a428SJonas Bonn 7169d02a428SJonas Bonn/* This is where the exception-return code begins... interrupts need to be 7179d02a428SJonas Bonn * disabled the rest of the way here because we can't afford to miss any 7189d02a428SJonas Bonn * interrupts that set NEED_RESCHED or SIGNALPENDING... really true? */ 7199d02a428SJonas Bonn 7209d02a428SJonas Bonn_syscall_check_work: 7219d02a428SJonas Bonn /* Here we need to disable interrupts */ 7229d02a428SJonas Bonn DISABLE_INTERRUPTS(r27,r29) 72378cdfb5cSStafford Horne TRACE_IRQS_OFF 7249d02a428SJonas Bonn l.lwz r30,TI_FLAGS(r10) 7259d02a428SJonas Bonn l.andi r30,r30,_TIF_WORK_MASK 7269d02a428SJonas Bonn l.sfne r30,r0 7279d02a428SJonas Bonn 7289d02a428SJonas Bonn l.bnf _syscall_resume_userspace 7299d02a428SJonas Bonn l.nop 7309d02a428SJonas Bonn 7319d02a428SJonas Bonn /* Work pending follows a different return path, so we need to 7329d02a428SJonas Bonn * make sure that all the call-saved registers get into pt_regs 7339d02a428SJonas Bonn * before branching... 7349d02a428SJonas Bonn */ 7359d02a428SJonas Bonn l.sw PT_GPR14(r1),r14 7369d02a428SJonas Bonn l.sw PT_GPR16(r1),r16 7379d02a428SJonas Bonn l.sw PT_GPR18(r1),r18 7389d02a428SJonas Bonn l.sw PT_GPR20(r1),r20 7399d02a428SJonas Bonn l.sw PT_GPR22(r1),r22 7409d02a428SJonas Bonn l.sw PT_GPR24(r1),r24 7419d02a428SJonas Bonn l.sw PT_GPR26(r1),r26 7429d02a428SJonas Bonn l.sw PT_GPR28(r1),r28 7439d02a428SJonas Bonn 7449d02a428SJonas Bonn /* _work_pending needs to be called with interrupts disabled */ 7459d02a428SJonas Bonn l.j _work_pending 7469d02a428SJonas Bonn l.nop 7479d02a428SJonas Bonn 7489d02a428SJonas Bonn_syscall_resume_userspace: 7499d02a428SJonas Bonn// ENABLE_INTERRUPTS(r29) 7509d02a428SJonas Bonn 7519d02a428SJonas Bonn 7529d02a428SJonas Bonn/* This is the hot path for returning to userspace from a syscall. If there's 7539d02a428SJonas Bonn * work to be done and the branch to _work_pending was taken above, then the 7549d02a428SJonas Bonn * return to userspace will be done via the normal exception return path... 7559d02a428SJonas Bonn * that path restores _all_ registers and will overwrite the "clobbered" 7569d02a428SJonas Bonn * registers with whatever garbage is in pt_regs -- that's OK because those 7579d02a428SJonas Bonn * registers are clobbered anyway and because the extra work is insignificant 7589d02a428SJonas Bonn * in the context of the extra work that _work_pending is doing. 7599d02a428SJonas Bonn 7609d02a428SJonas Bonn/* Once again, syscalls are special and only guarantee to preserve the 7619d02a428SJonas Bonn * same registers as a normal function call */ 7629d02a428SJonas Bonn 7639d02a428SJonas Bonn/* The assumption here is that the registers r14-r28 (even) are untouched and 7649d02a428SJonas Bonn * don't need to be restored... be sure that that's really the case! 7659d02a428SJonas Bonn */ 7669d02a428SJonas Bonn 7679d02a428SJonas Bonn/* This is still too much... we should only be restoring what we actually 7689d02a428SJonas Bonn * clobbered... we should even be using 'scratch' (odd) regs above so that 7699d02a428SJonas Bonn * we don't need to restore anything, hardly... 7709d02a428SJonas Bonn */ 7719d02a428SJonas Bonn 7729d02a428SJonas Bonn l.lwz r2,PT_GPR2(r1) 7739d02a428SJonas Bonn 7749d02a428SJonas Bonn /* Restore args */ 7759d02a428SJonas Bonn /* r3-r8 are technically clobbered, but syscall restart needs these 7769d02a428SJonas Bonn * to be restored... 7779d02a428SJonas Bonn */ 7789d02a428SJonas Bonn l.lwz r3,PT_GPR3(r1) 7799d02a428SJonas Bonn l.lwz r4,PT_GPR4(r1) 7809d02a428SJonas Bonn l.lwz r5,PT_GPR5(r1) 7819d02a428SJonas Bonn l.lwz r6,PT_GPR6(r1) 7829d02a428SJonas Bonn l.lwz r7,PT_GPR7(r1) 7839d02a428SJonas Bonn l.lwz r8,PT_GPR8(r1) 7849d02a428SJonas Bonn 7859d02a428SJonas Bonn l.lwz r9,PT_GPR9(r1) 7869d02a428SJonas Bonn l.lwz r10,PT_GPR10(r1) 7879d02a428SJonas Bonn l.lwz r11,PT_GPR11(r1) 7889d02a428SJonas Bonn 7899d02a428SJonas Bonn /* r30 is the only register we clobber in the fast path */ 7909d02a428SJonas Bonn l.lwz r30,PT_GPR30(r1) 7919d02a428SJonas Bonn 7929d02a428SJonas Bonn /* Here we use r13-r19 (odd) as scratch regs */ 7939d02a428SJonas Bonn l.lwz r13,PT_PC(r1) 7949d02a428SJonas Bonn l.lwz r15,PT_SR(r1) 7959d02a428SJonas Bonn l.lwz r1,PT_SP(r1) 7969d02a428SJonas Bonn /* Interrupts need to be disabled for setting EPCR and ESR 7979d02a428SJonas Bonn * so that another interrupt doesn't come in here and clobber 7989d02a428SJonas Bonn * them before we can use them for our l.rfe */ 7999d02a428SJonas Bonn DISABLE_INTERRUPTS(r17,r19) 8009d02a428SJonas Bonn l.mtspr r0,r13,SPR_EPCR_BASE 8019d02a428SJonas Bonn l.mtspr r0,r15,SPR_ESR_BASE 8029d02a428SJonas Bonn l.rfe 8039d02a428SJonas Bonn 8049d02a428SJonas Bonn/* End of hot path! 8059d02a428SJonas Bonn * Keep the below tracing and error handling out of the hot path... 8069d02a428SJonas Bonn*/ 8079d02a428SJonas Bonn 8089d02a428SJonas Bonn_syscall_trace_enter: 8099d02a428SJonas Bonn /* Here we pass pt_regs to do_syscall_trace_enter. Make sure 8109d02a428SJonas Bonn * that function is really getting all the info it needs as 8119d02a428SJonas Bonn * pt_regs isn't a complete set of userspace regs, just the 8129d02a428SJonas Bonn * ones relevant to the syscall... 8139d02a428SJonas Bonn * 8149d02a428SJonas Bonn * Note use of delay slot for setting argument. 8159d02a428SJonas Bonn */ 8169d02a428SJonas Bonn l.jal do_syscall_trace_enter 8179d02a428SJonas Bonn l.addi r3,r1,0 8189d02a428SJonas Bonn 8199d02a428SJonas Bonn /* Restore arguments (not preserved across do_syscall_trace_enter) 8209d02a428SJonas Bonn * so that we can do the syscall for real and return to the syscall 8219d02a428SJonas Bonn * hot path. 8229d02a428SJonas Bonn */ 8236cbe5e95SJonas Bonn l.lwz r11,PT_GPR11(r1) 8249d02a428SJonas Bonn l.lwz r3,PT_GPR3(r1) 8259d02a428SJonas Bonn l.lwz r4,PT_GPR4(r1) 8269d02a428SJonas Bonn l.lwz r5,PT_GPR5(r1) 8279d02a428SJonas Bonn l.lwz r6,PT_GPR6(r1) 8289d02a428SJonas Bonn l.lwz r7,PT_GPR7(r1) 8299d02a428SJonas Bonn 8309d02a428SJonas Bonn l.j _syscall_check 8319d02a428SJonas Bonn l.lwz r8,PT_GPR8(r1) 8329d02a428SJonas Bonn 8339d02a428SJonas Bonn_syscall_trace_leave: 8349d02a428SJonas Bonn l.jal do_syscall_trace_leave 8359d02a428SJonas Bonn l.addi r3,r1,0 8369d02a428SJonas Bonn 8379d02a428SJonas Bonn l.j _syscall_check_work 8389d02a428SJonas Bonn l.nop 8399d02a428SJonas Bonn 8409d02a428SJonas Bonn_syscall_badsys: 8419d02a428SJonas Bonn /* Here we effectively pretend to have executed an imaginary 8429d02a428SJonas Bonn * syscall that returns -ENOSYS and then return to the regular 8439d02a428SJonas Bonn * syscall hot path. 8449d02a428SJonas Bonn * Note that "return value" is set in the delay slot... 8459d02a428SJonas Bonn */ 8469d02a428SJonas Bonn l.j _syscall_return 8479d02a428SJonas Bonn l.addi r11,r0,-ENOSYS 8489d02a428SJonas Bonn 8499d02a428SJonas Bonn/******* END SYSCALL HANDLING *******/ 8509d02a428SJonas Bonn 851*27267655SStafford Horne/* ---[ 0xd00: Floating Point exception ]-------------------------------- */ 8529d02a428SJonas Bonn 853*27267655SStafford HorneEXCEPTION_ENTRY(_fpe_trap_handler) 854*27267655SStafford Horne CLEAR_LWA_FLAG(r3) 855*27267655SStafford Horne /* r4: EA of fault (set by EXCEPTION_HANDLE) */ 856*27267655SStafford Horne l.jal do_fpe_trap 857*27267655SStafford Horne l.addi r3,r1,0 /* pt_regs */ 858*27267655SStafford Horne 859*27267655SStafford Horne l.j _ret_from_exception 860*27267655SStafford Horne l.nop 8619d02a428SJonas Bonn 8629d02a428SJonas Bonn/* ---[ 0xe00: Trap exception ]------------------------------------------ */ 8639d02a428SJonas Bonn 8649d02a428SJonas BonnEXCEPTION_ENTRY(_trap_handler) 86563104c06SStefan Kristiansson CLEAR_LWA_FLAG(r3) 8669d02a428SJonas Bonn /* r4: EA of fault (set by EXCEPTION_HANDLE) */ 8679d02a428SJonas Bonn l.jal do_trap 8689d02a428SJonas Bonn l.addi r3,r1,0 /* pt_regs */ 8699d02a428SJonas Bonn 8709d02a428SJonas Bonn l.j _ret_from_exception 8719d02a428SJonas Bonn l.nop 8729d02a428SJonas Bonn 8739d02a428SJonas Bonn/* ---[ 0xf00: Reserved exception ]-------------------------------------- */ 8749d02a428SJonas Bonn 8759d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0xf00,0xf00) 8769d02a428SJonas Bonn 8779d02a428SJonas Bonn/* ---[ 0x1000: Reserved exception ]------------------------------------- */ 8789d02a428SJonas Bonn 8799d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1000,0x1000) 8809d02a428SJonas Bonn 8819d02a428SJonas Bonn/* ---[ 0x1100: Reserved exception ]------------------------------------- */ 8829d02a428SJonas Bonn 8839d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1100,0x1100) 8849d02a428SJonas Bonn 8859d02a428SJonas Bonn/* ---[ 0x1200: Reserved exception ]------------------------------------- */ 8869d02a428SJonas Bonn 8879d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1200,0x1200) 8889d02a428SJonas Bonn 8899d02a428SJonas Bonn/* ---[ 0x1300: Reserved exception ]------------------------------------- */ 8909d02a428SJonas Bonn 8919d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1300,0x1300) 8929d02a428SJonas Bonn 8939d02a428SJonas Bonn/* ---[ 0x1400: Reserved exception ]------------------------------------- */ 8949d02a428SJonas Bonn 8959d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1400,0x1400) 8969d02a428SJonas Bonn 8979d02a428SJonas Bonn/* ---[ 0x1500: Reserved exception ]------------------------------------- */ 8989d02a428SJonas Bonn 8999d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1500,0x1500) 9009d02a428SJonas Bonn 9019d02a428SJonas Bonn/* ---[ 0x1600: Reserved exception ]------------------------------------- */ 9029d02a428SJonas Bonn 9039d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1600,0x1600) 9049d02a428SJonas Bonn 9059d02a428SJonas Bonn/* ---[ 0x1700: Reserved exception ]------------------------------------- */ 9069d02a428SJonas Bonn 9079d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1700,0x1700) 9089d02a428SJonas Bonn 9099d02a428SJonas Bonn/* ---[ 0x1800: Reserved exception ]------------------------------------- */ 9109d02a428SJonas Bonn 9119d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1800,0x1800) 9129d02a428SJonas Bonn 9139d02a428SJonas Bonn/* ---[ 0x1900: Reserved exception ]------------------------------------- */ 9149d02a428SJonas Bonn 9159d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1900,0x1900) 9169d02a428SJonas Bonn 9179d02a428SJonas Bonn/* ---[ 0x1a00: Reserved exception ]------------------------------------- */ 9189d02a428SJonas Bonn 9199d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1a00,0x1a00) 9209d02a428SJonas Bonn 9219d02a428SJonas Bonn/* ---[ 0x1b00: Reserved exception ]------------------------------------- */ 9229d02a428SJonas Bonn 9239d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1b00,0x1b00) 9249d02a428SJonas Bonn 9259d02a428SJonas Bonn/* ---[ 0x1c00: Reserved exception ]------------------------------------- */ 9269d02a428SJonas Bonn 9279d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1c00,0x1c00) 9289d02a428SJonas Bonn 9299d02a428SJonas Bonn/* ---[ 0x1d00: Reserved exception ]------------------------------------- */ 9309d02a428SJonas Bonn 9319d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1d00,0x1d00) 9329d02a428SJonas Bonn 9339d02a428SJonas Bonn/* ---[ 0x1e00: Reserved exception ]------------------------------------- */ 9349d02a428SJonas Bonn 9359d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1e00,0x1e00) 9369d02a428SJonas Bonn 9379d02a428SJonas Bonn/* ---[ 0x1f00: Reserved exception ]------------------------------------- */ 9389d02a428SJonas Bonn 9399d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1f00,0x1f00) 9409d02a428SJonas Bonn 9419d02a428SJonas Bonn/* ========================================================[ return ] === */ 9429d02a428SJonas Bonn 9439d02a428SJonas Bonn_resume_userspace: 9449d02a428SJonas Bonn DISABLE_INTERRUPTS(r3,r4) 94578cdfb5cSStafford Horne TRACE_IRQS_OFF 94610f67dbfSJonas Bonn l.lwz r4,TI_FLAGS(r10) 94710f67dbfSJonas Bonn l.andi r13,r4,_TIF_WORK_MASK 94810f67dbfSJonas Bonn l.sfeqi r13,0 94910f67dbfSJonas Bonn l.bf _restore_all 9509d02a428SJonas Bonn l.nop 9519d02a428SJonas Bonn 95210f67dbfSJonas Bonn_work_pending: 95310f67dbfSJonas Bonn l.lwz r5,PT_ORIG_GPR11(r1) 95410f67dbfSJonas Bonn l.sfltsi r5,0 95510f67dbfSJonas Bonn l.bnf 1f 95610f67dbfSJonas Bonn l.nop 95710f67dbfSJonas Bonn l.andi r5,r5,0 95810f67dbfSJonas Bonn1: 95910f67dbfSJonas Bonn l.jal do_work_pending 96010f67dbfSJonas Bonn l.ori r3,r1,0 /* pt_regs */ 96110f67dbfSJonas Bonn 96210f67dbfSJonas Bonn l.sfeqi r11,0 96310f67dbfSJonas Bonn l.bf _restore_all 96410f67dbfSJonas Bonn l.nop 96510f67dbfSJonas Bonn l.sfltsi r11,0 96610f67dbfSJonas Bonn l.bnf 1f 96710f67dbfSJonas Bonn l.nop 96810f67dbfSJonas Bonn l.and r11,r11,r0 96910f67dbfSJonas Bonn l.ori r11,r11,__NR_restart_syscall 97010f67dbfSJonas Bonn l.j _syscall_check_trace_enter 97110f67dbfSJonas Bonn l.nop 97210f67dbfSJonas Bonn1: 97310f67dbfSJonas Bonn l.lwz r11,PT_ORIG_GPR11(r1) 97410f67dbfSJonas Bonn /* Restore arg registers */ 97510f67dbfSJonas Bonn l.lwz r3,PT_GPR3(r1) 97610f67dbfSJonas Bonn l.lwz r4,PT_GPR4(r1) 97710f67dbfSJonas Bonn l.lwz r5,PT_GPR5(r1) 97810f67dbfSJonas Bonn l.lwz r6,PT_GPR6(r1) 97910f67dbfSJonas Bonn l.lwz r7,PT_GPR7(r1) 98010f67dbfSJonas Bonn l.j _syscall_check_trace_enter 98110f67dbfSJonas Bonn l.lwz r8,PT_GPR8(r1) 98210f67dbfSJonas Bonn 9839d02a428SJonas Bonn_restore_all: 98478cdfb5cSStafford Horne#ifdef CONFIG_TRACE_IRQFLAGS 98578cdfb5cSStafford Horne l.lwz r4,PT_SR(r1) 98678cdfb5cSStafford Horne l.andi r3,r4,(SPR_SR_IEE|SPR_SR_TEE) 98778cdfb5cSStafford Horne l.sfeq r3,r0 /* skip trace if irqs were off */ 98878cdfb5cSStafford Horne l.bf skip_hardirqs_on 98978cdfb5cSStafford Horne l.nop 99078cdfb5cSStafford Horne TRACE_IRQS_ON 99178cdfb5cSStafford Horneskip_hardirqs_on: 99278cdfb5cSStafford Horne#endif 9939d02a428SJonas Bonn RESTORE_ALL 9949d02a428SJonas Bonn /* This returns to userspace code */ 9959d02a428SJonas Bonn 9969d02a428SJonas Bonn 9979d02a428SJonas BonnENTRY(_ret_from_intr) 9989d02a428SJonas BonnENTRY(_ret_from_exception) 9999d02a428SJonas Bonn l.lwz r4,PT_SR(r1) 10009d02a428SJonas Bonn l.andi r3,r4,SPR_SR_SM 10019d02a428SJonas Bonn l.sfeqi r3,0 10029d02a428SJonas Bonn l.bnf _restore_all 10039d02a428SJonas Bonn l.nop 10049d02a428SJonas Bonn l.j _resume_userspace 10059d02a428SJonas Bonn l.nop 10069d02a428SJonas Bonn 10079d02a428SJonas BonnENTRY(ret_from_fork) 10089d02a428SJonas Bonn l.jal schedule_tail 10099d02a428SJonas Bonn l.nop 10109d02a428SJonas Bonn 1011cbf23cf1SJonas Bonn /* Check if we are a kernel thread */ 1012cbf23cf1SJonas Bonn l.sfeqi r20,0 1013cbf23cf1SJonas Bonn l.bf 1f 1014cbf23cf1SJonas Bonn l.nop 1015cbf23cf1SJonas Bonn 1016cbf23cf1SJonas Bonn /* ...we are a kernel thread so invoke the requested callback */ 1017cbf23cf1SJonas Bonn l.jalr r20 1018cbf23cf1SJonas Bonn l.or r3,r22,r0 1019cbf23cf1SJonas Bonn 1020cbf23cf1SJonas Bonn1: 10219d02a428SJonas Bonn /* _syscall_returns expect r11 to contain return value */ 10229d02a428SJonas Bonn l.lwz r11,PT_GPR11(r1) 10239d02a428SJonas Bonn 10249d02a428SJonas Bonn /* The syscall fast path return expects call-saved registers 1025840b66c2SStafford Horne * r14-r28 to be untouched, so we restore them here as they 10269d02a428SJonas Bonn * will have been effectively clobbered when arriving here 10279d02a428SJonas Bonn * via the call to switch() 10289d02a428SJonas Bonn */ 10299d02a428SJonas Bonn l.lwz r14,PT_GPR14(r1) 10309d02a428SJonas Bonn l.lwz r16,PT_GPR16(r1) 10319d02a428SJonas Bonn l.lwz r18,PT_GPR18(r1) 10329d02a428SJonas Bonn l.lwz r20,PT_GPR20(r1) 10339d02a428SJonas Bonn l.lwz r22,PT_GPR22(r1) 10349d02a428SJonas Bonn l.lwz r24,PT_GPR24(r1) 10359d02a428SJonas Bonn l.lwz r26,PT_GPR26(r1) 10369d02a428SJonas Bonn l.lwz r28,PT_GPR28(r1) 10379d02a428SJonas Bonn 10389d02a428SJonas Bonn l.j _syscall_return 10399d02a428SJonas Bonn l.nop 10409d02a428SJonas Bonn 10419d02a428SJonas Bonn/* ========================================================[ switch ] === */ 10429d02a428SJonas Bonn 10439d02a428SJonas Bonn/* 10449d02a428SJonas Bonn * This routine switches between two different tasks. The process 10459d02a428SJonas Bonn * state of one is saved on its kernel stack. Then the state 10469d02a428SJonas Bonn * of the other is restored from its kernel stack. The memory 10479d02a428SJonas Bonn * management hardware is updated to the second process's state. 10489d02a428SJonas Bonn * Finally, we can return to the second process, via the 'return'. 10499d02a428SJonas Bonn * 10509d02a428SJonas Bonn * Note: there are two ways to get to the "going out" portion 10519d02a428SJonas Bonn * of this code; either by coming in via the entry (_switch) 10529d02a428SJonas Bonn * or via "fork" which must set up an environment equivalent 10539d02a428SJonas Bonn * to the "_switch" path. If you change this (or in particular, the 10549d02a428SJonas Bonn * SAVE_REGS macro), you'll have to change the fork code also. 10559d02a428SJonas Bonn */ 10569d02a428SJonas Bonn 10579d02a428SJonas Bonn 10589d02a428SJonas Bonn/* _switch MUST never lay on page boundry, cause it runs from 10599d02a428SJonas Bonn * effective addresses and beeing interrupted by iTLB miss would kill it. 1060840b66c2SStafford Horne * dTLB miss seems to never accour in the bad place since data accesses 10619d02a428SJonas Bonn * are from task structures which are always page aligned. 10629d02a428SJonas Bonn * 1063840b66c2SStafford Horne * The problem happens in RESTORE_ALL where we first set the EPCR 10649d02a428SJonas Bonn * register, then load the previous register values and only at the end call 10659d02a428SJonas Bonn * the l.rfe instruction. If get TLB miss in beetwen the EPCR register gets 10669d02a428SJonas Bonn * garbled and we end up calling l.rfe with the wrong EPCR. (same probably 10679d02a428SJonas Bonn * holds for ESR) 10689d02a428SJonas Bonn * 10699d02a428SJonas Bonn * To avoid this problems it is sufficient to align _switch to 10709d02a428SJonas Bonn * some nice round number smaller than it's size... 10719d02a428SJonas Bonn */ 10729d02a428SJonas Bonn 10739d02a428SJonas Bonn/* ABI rules apply here... we either enter _switch via schedule() or via 10749d02a428SJonas Bonn * an imaginary call to which we shall return at return_from_fork. Either 10759d02a428SJonas Bonn * way, we are a function call and only need to preserve the callee-saved 10769d02a428SJonas Bonn * registers when we return. As such, we don't need to save the registers 10779d02a428SJonas Bonn * on the stack that we won't be returning as they were... 10789d02a428SJonas Bonn */ 10799d02a428SJonas Bonn 10809d02a428SJonas Bonn .align 0x400 10819d02a428SJonas BonnENTRY(_switch) 10829d02a428SJonas Bonn /* We don't store SR as _switch only gets called in a context where 10839d02a428SJonas Bonn * the SR will be the same going in and coming out... */ 10849d02a428SJonas Bonn 10859d02a428SJonas Bonn /* Set up new pt_regs struct for saving task state */ 10869d02a428SJonas Bonn l.addi r1,r1,-(INT_FRAME_SIZE) 10879d02a428SJonas Bonn 10889d02a428SJonas Bonn /* No need to store r1/PT_SP as it goes into KSP below */ 10899d02a428SJonas Bonn l.sw PT_GPR2(r1),r2 10909d02a428SJonas Bonn l.sw PT_GPR9(r1),r9 1091840b66c2SStafford Horne 1092840b66c2SStafford Horne /* Save callee-saved registers to the new pt_regs */ 10939d02a428SJonas Bonn l.sw PT_GPR14(r1),r14 10949d02a428SJonas Bonn l.sw PT_GPR16(r1),r16 10959d02a428SJonas Bonn l.sw PT_GPR18(r1),r18 10969d02a428SJonas Bonn l.sw PT_GPR20(r1),r20 10979d02a428SJonas Bonn l.sw PT_GPR22(r1),r22 10989d02a428SJonas Bonn l.sw PT_GPR24(r1),r24 10999d02a428SJonas Bonn l.sw PT_GPR26(r1),r26 11009d02a428SJonas Bonn l.sw PT_GPR28(r1),r28 11019d02a428SJonas Bonn l.sw PT_GPR30(r1),r30 11029d02a428SJonas Bonn 110363d7f9f1SStafford Horne /* Store the old FPU state to new pt_regs */ 110463d7f9f1SStafford Horne l.mfspr r29,r0,SPR_FPCSR 110563d7f9f1SStafford Horne l.sw PT_FPCSR(r1),r29 110663d7f9f1SStafford Horne 11079d02a428SJonas Bonn l.addi r11,r10,0 /* Save old 'current' to 'last' return value*/ 11089d02a428SJonas Bonn 11099d02a428SJonas Bonn /* We use thread_info->ksp for storing the address of the above 11109d02a428SJonas Bonn * structure so that we can get back to it later... we don't want 11119d02a428SJonas Bonn * to lose the value of thread_info->ksp, though, so store it as 11129d02a428SJonas Bonn * pt_regs->sp so that we can easily restore it when we are made 11139d02a428SJonas Bonn * live again... 11149d02a428SJonas Bonn */ 11159d02a428SJonas Bonn 11169d02a428SJonas Bonn /* Save the old value of thread_info->ksp as pt_regs->sp */ 11179d02a428SJonas Bonn l.lwz r29,TI_KSP(r10) 11189d02a428SJonas Bonn l.sw PT_SP(r1),r29 11199d02a428SJonas Bonn 11209d02a428SJonas Bonn /* Swap kernel stack pointers */ 11219d02a428SJonas Bonn l.sw TI_KSP(r10),r1 /* Save old stack pointer */ 11229d02a428SJonas Bonn l.or r10,r4,r0 /* Set up new current_thread_info */ 11239d02a428SJonas Bonn l.lwz r1,TI_KSP(r10) /* Load new stack pointer */ 11249d02a428SJonas Bonn 11259d02a428SJonas Bonn /* Restore the old value of thread_info->ksp */ 11269d02a428SJonas Bonn l.lwz r29,PT_SP(r1) 11279d02a428SJonas Bonn l.sw TI_KSP(r10),r29 11289d02a428SJonas Bonn 112963d7f9f1SStafford Horne /* Restore the old value of FPCSR */ 113063d7f9f1SStafford Horne l.lwz r29,PT_FPCSR(r1) 113163d7f9f1SStafford Horne l.mtspr r0,r29,SPR_FPCSR 113263d7f9f1SStafford Horne 11339d02a428SJonas Bonn /* ...and restore the registers, except r11 because the return value 11349d02a428SJonas Bonn * has already been set above. 11359d02a428SJonas Bonn */ 11369d02a428SJonas Bonn l.lwz r2,PT_GPR2(r1) 11379d02a428SJonas Bonn l.lwz r9,PT_GPR9(r1) 11389d02a428SJonas Bonn /* No need to restore r10 */ 11399d02a428SJonas Bonn /* ...and do not restore r11 */ 11409d02a428SJonas Bonn 1141840b66c2SStafford Horne /* Restore callee-saved registers */ 11429d02a428SJonas Bonn l.lwz r14,PT_GPR14(r1) 11439d02a428SJonas Bonn l.lwz r16,PT_GPR16(r1) 11449d02a428SJonas Bonn l.lwz r18,PT_GPR18(r1) 11459d02a428SJonas Bonn l.lwz r20,PT_GPR20(r1) 11469d02a428SJonas Bonn l.lwz r22,PT_GPR22(r1) 11479d02a428SJonas Bonn l.lwz r24,PT_GPR24(r1) 11489d02a428SJonas Bonn l.lwz r26,PT_GPR26(r1) 11499d02a428SJonas Bonn l.lwz r28,PT_GPR28(r1) 11509d02a428SJonas Bonn l.lwz r30,PT_GPR30(r1) 11519d02a428SJonas Bonn 11529d02a428SJonas Bonn /* Unwind stack to pre-switch state */ 11539d02a428SJonas Bonn l.addi r1,r1,(INT_FRAME_SIZE) 11549d02a428SJonas Bonn 1155287ad220SJonas Bonn /* Return via the link-register back to where we 'came from', where 1156287ad220SJonas Bonn * that may be either schedule(), ret_from_fork(), or 1157287ad220SJonas Bonn * ret_from_kernel_thread(). If we are returning to a new thread, 1158287ad220SJonas Bonn * we are expected to have set up the arg to schedule_tail already, 1159287ad220SJonas Bonn * hence we do so here unconditionally: 1160287ad220SJonas Bonn */ 1161ae6fef17SJonas Bonn l.lwz r3,TI_TASK(r3) /* Load 'prev' as schedule_tail arg */ 11629d02a428SJonas Bonn l.jr r9 11639d02a428SJonas Bonn l.nop 11649d02a428SJonas Bonn 11659d02a428SJonas Bonn/* ==================================================================== */ 11669d02a428SJonas Bonn 11679d02a428SJonas Bonn/* These all use the delay slot for setting the argument register, so the 11689d02a428SJonas Bonn * jump is always happening after the l.addi instruction. 11699d02a428SJonas Bonn * 11709d02a428SJonas Bonn * These are all just wrappers that don't touch the link-register r9, so the 11719d02a428SJonas Bonn * return from the "real" syscall function will return back to the syscall 11729d02a428SJonas Bonn * code that did the l.jal that brought us here. 11739d02a428SJonas Bonn */ 11749d02a428SJonas Bonn 11759d02a428SJonas Bonn/* fork requires that we save all the callee-saved registers because they 11769d02a428SJonas Bonn * are all effectively clobbered by the call to _switch. Here we store 11779d02a428SJonas Bonn * all the registers that aren't touched by the syscall fast path and thus 11789d02a428SJonas Bonn * weren't saved there. 11799d02a428SJonas Bonn */ 11809d02a428SJonas Bonn 11819d02a428SJonas Bonn_fork_save_extra_regs_and_call: 11829d02a428SJonas Bonn l.sw PT_GPR14(r1),r14 11839d02a428SJonas Bonn l.sw PT_GPR16(r1),r16 11849d02a428SJonas Bonn l.sw PT_GPR18(r1),r18 11859d02a428SJonas Bonn l.sw PT_GPR20(r1),r20 11869d02a428SJonas Bonn l.sw PT_GPR22(r1),r22 11879d02a428SJonas Bonn l.sw PT_GPR24(r1),r24 11889d02a428SJonas Bonn l.sw PT_GPR26(r1),r26 11899d02a428SJonas Bonn l.jr r29 11909d02a428SJonas Bonn l.sw PT_GPR28(r1),r28 11919d02a428SJonas Bonn 119239d91a9eSAl ViroENTRY(__sys_clone) 119339d91a9eSAl Viro l.movhi r29,hi(sys_clone) 11949d02a428SJonas Bonn l.j _fork_save_extra_regs_and_call 119507baf50aSStafford Horne l.ori r29,r29,lo(sys_clone) 11969d02a428SJonas Bonn 1197433fe39fSStafford HorneENTRY(__sys_clone3) 1198433fe39fSStafford Horne l.movhi r29,hi(sys_clone3) 1199433fe39fSStafford Horne l.j _fork_save_extra_regs_and_call 1200433fe39fSStafford Horne l.ori r29,r29,lo(sys_clone3) 1201433fe39fSStafford Horne 120239d91a9eSAl ViroENTRY(__sys_fork) 120339d91a9eSAl Viro l.movhi r29,hi(sys_fork) 12049d02a428SJonas Bonn l.j _fork_save_extra_regs_and_call 120507baf50aSStafford Horne l.ori r29,r29,lo(sys_fork) 12069d02a428SJonas Bonn 12079d02a428SJonas BonnENTRY(sys_rt_sigreturn) 1208c7990219SJonas Bonn l.jal _sys_rt_sigreturn 12099d02a428SJonas Bonn l.addi r3,r1,0 1210c7990219SJonas Bonn l.sfne r30,r0 1211c7990219SJonas Bonn l.bnf _no_syscall_trace 1212c7990219SJonas Bonn l.nop 1213c7990219SJonas Bonn l.jal do_syscall_trace_leave 1214c7990219SJonas Bonn l.addi r3,r1,0 1215c7990219SJonas Bonn_no_syscall_trace: 1216c7990219SJonas Bonn l.j _resume_userspace 1217c7990219SJonas Bonn l.nop 12189d02a428SJonas Bonn 12199d02a428SJonas Bonn/* This is a catch-all syscall for atomic instructions for the OpenRISC 1000. 12209d02a428SJonas Bonn * The functions takes a variable number of parameters depending on which 12219d02a428SJonas Bonn * particular flavour of atomic you want... parameter 1 is a flag identifying 12229d02a428SJonas Bonn * the atomic in question. Currently, this function implements the 12239d02a428SJonas Bonn * following variants: 12249d02a428SJonas Bonn * 12259d02a428SJonas Bonn * XCHG: 12269d02a428SJonas Bonn * @flag: 1 12279d02a428SJonas Bonn * @ptr1: 12289d02a428SJonas Bonn * @ptr2: 12299d02a428SJonas Bonn * Atomically exchange the values in pointers 1 and 2. 12309d02a428SJonas Bonn * 12319d02a428SJonas Bonn */ 12329d02a428SJonas Bonn 12339d02a428SJonas BonnENTRY(sys_or1k_atomic) 12349d02a428SJonas Bonn /* FIXME: This ignores r3 and always does an XCHG */ 12359d02a428SJonas Bonn DISABLE_INTERRUPTS(r17,r19) 1236207e715fSJonas Bonn l.lwz r29,0(r4) 1237207e715fSJonas Bonn l.lwz r27,0(r5) 1238207e715fSJonas Bonn l.sw 0(r4),r27 1239207e715fSJonas Bonn l.sw 0(r5),r29 12409d02a428SJonas Bonn ENABLE_INTERRUPTS(r17) 12419d02a428SJonas Bonn l.jr r9 12429d02a428SJonas Bonn l.or r11,r0,r0 12439d02a428SJonas Bonn 12449d02a428SJonas Bonn/* ============================================================[ EOF ]=== */ 1245