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 ;\ 1099d02a428SJonas Bonn l.lwz r2,PT_GPR2(r1) ;\ 1109d02a428SJonas Bonn l.lwz r3,PT_GPR3(r1) ;\ 1119d02a428SJonas Bonn l.lwz r4,PT_GPR4(r1) ;\ 1129d02a428SJonas Bonn l.lwz r5,PT_GPR5(r1) ;\ 1139d02a428SJonas Bonn l.lwz r6,PT_GPR6(r1) ;\ 1149d02a428SJonas Bonn l.lwz r7,PT_GPR7(r1) ;\ 1159d02a428SJonas Bonn l.lwz r8,PT_GPR8(r1) ;\ 1169d02a428SJonas Bonn l.lwz r9,PT_GPR9(r1) ;\ 1179d02a428SJonas Bonn l.lwz r10,PT_GPR10(r1) ;\ 1189d02a428SJonas Bonn l.lwz r11,PT_GPR11(r1) ;\ 1199d02a428SJonas Bonn l.lwz r12,PT_GPR12(r1) ;\ 1209d02a428SJonas Bonn l.lwz r13,PT_GPR13(r1) ;\ 1219d02a428SJonas Bonn l.lwz r14,PT_GPR14(r1) ;\ 1229d02a428SJonas Bonn l.lwz r15,PT_GPR15(r1) ;\ 1239d02a428SJonas Bonn l.lwz r16,PT_GPR16(r1) ;\ 1249d02a428SJonas Bonn l.lwz r17,PT_GPR17(r1) ;\ 1259d02a428SJonas Bonn l.lwz r18,PT_GPR18(r1) ;\ 1269d02a428SJonas Bonn l.lwz r19,PT_GPR19(r1) ;\ 1279d02a428SJonas Bonn l.lwz r20,PT_GPR20(r1) ;\ 1289d02a428SJonas Bonn l.lwz r21,PT_GPR21(r1) ;\ 1299d02a428SJonas Bonn l.lwz r22,PT_GPR22(r1) ;\ 1309d02a428SJonas Bonn l.lwz r23,PT_GPR23(r1) ;\ 1319d02a428SJonas Bonn l.lwz r24,PT_GPR24(r1) ;\ 1329d02a428SJonas Bonn l.lwz r25,PT_GPR25(r1) ;\ 1339d02a428SJonas Bonn l.lwz r26,PT_GPR26(r1) ;\ 1349d02a428SJonas Bonn l.lwz r27,PT_GPR27(r1) ;\ 1359d02a428SJonas Bonn l.lwz r28,PT_GPR28(r1) ;\ 1369d02a428SJonas Bonn l.lwz r29,PT_GPR29(r1) ;\ 1379d02a428SJonas Bonn l.lwz r30,PT_GPR30(r1) ;\ 1389d02a428SJonas Bonn l.lwz r31,PT_GPR31(r1) ;\ 1399d02a428SJonas Bonn l.lwz r1,PT_SP(r1) ;\ 1409d02a428SJonas Bonn l.rfe 1419d02a428SJonas Bonn 1429d02a428SJonas Bonn 1439d02a428SJonas Bonn#define EXCEPTION_ENTRY(handler) \ 1449d02a428SJonas Bonn .global handler ;\ 1459d02a428SJonas Bonnhandler: ;\ 1469d02a428SJonas Bonn /* r1, EPCR, ESR a already saved */ ;\ 1479d02a428SJonas Bonn l.sw PT_GPR2(r1),r2 ;\ 1489d02a428SJonas Bonn l.sw PT_GPR3(r1),r3 ;\ 1499d02a428SJonas Bonn /* r4 already save */ ;\ 1509d02a428SJonas Bonn l.sw PT_GPR5(r1),r5 ;\ 1519d02a428SJonas Bonn l.sw PT_GPR6(r1),r6 ;\ 1529d02a428SJonas Bonn l.sw PT_GPR7(r1),r7 ;\ 1539d02a428SJonas Bonn l.sw PT_GPR8(r1),r8 ;\ 1549d02a428SJonas Bonn l.sw PT_GPR9(r1),r9 ;\ 1559d02a428SJonas Bonn /* r10 already saved */ ;\ 1569d02a428SJonas Bonn l.sw PT_GPR11(r1),r11 ;\ 1579d02a428SJonas Bonn /* r12 already saved */ ;\ 1589d02a428SJonas Bonn l.sw PT_GPR13(r1),r13 ;\ 1599d02a428SJonas Bonn l.sw PT_GPR14(r1),r14 ;\ 1609d02a428SJonas Bonn l.sw PT_GPR15(r1),r15 ;\ 1619d02a428SJonas Bonn l.sw PT_GPR16(r1),r16 ;\ 1629d02a428SJonas Bonn l.sw PT_GPR17(r1),r17 ;\ 1639d02a428SJonas Bonn l.sw PT_GPR18(r1),r18 ;\ 1649d02a428SJonas Bonn l.sw PT_GPR19(r1),r19 ;\ 1659d02a428SJonas Bonn l.sw PT_GPR20(r1),r20 ;\ 1669d02a428SJonas Bonn l.sw PT_GPR21(r1),r21 ;\ 1679d02a428SJonas Bonn l.sw PT_GPR22(r1),r22 ;\ 1689d02a428SJonas Bonn l.sw PT_GPR23(r1),r23 ;\ 1699d02a428SJonas Bonn l.sw PT_GPR24(r1),r24 ;\ 1709d02a428SJonas Bonn l.sw PT_GPR25(r1),r25 ;\ 1719d02a428SJonas Bonn l.sw PT_GPR26(r1),r26 ;\ 1729d02a428SJonas Bonn l.sw PT_GPR27(r1),r27 ;\ 1739d02a428SJonas Bonn l.sw PT_GPR28(r1),r28 ;\ 1749d02a428SJonas Bonn l.sw PT_GPR29(r1),r29 ;\ 1759d02a428SJonas Bonn /* r30 already save */ ;\ 1769d02a428SJonas Bonn/* l.sw PT_GPR30(r1),r30*/ ;\ 1779d02a428SJonas Bonn l.sw PT_GPR31(r1),r31 ;\ 17878cdfb5cSStafford Horne TRACE_IRQS_OFF_ENTRY ;\ 1796cbe5e95SJonas Bonn /* Store -1 in orig_gpr11 for non-syscall exceptions */ ;\ 1806cbe5e95SJonas Bonn l.addi r30,r0,-1 ;\ 1816cbe5e95SJonas Bonn l.sw PT_ORIG_GPR11(r1),r30 1829d02a428SJonas Bonn 1839d02a428SJonas Bonn#define UNHANDLED_EXCEPTION(handler,vector) \ 1849d02a428SJonas Bonn .global handler ;\ 1859d02a428SJonas Bonnhandler: ;\ 1869d02a428SJonas Bonn /* r1, EPCR, ESR already saved */ ;\ 1879d02a428SJonas Bonn l.sw PT_GPR2(r1),r2 ;\ 1889d02a428SJonas Bonn l.sw PT_GPR3(r1),r3 ;\ 1899d02a428SJonas Bonn l.sw PT_GPR5(r1),r5 ;\ 1909d02a428SJonas Bonn l.sw PT_GPR6(r1),r6 ;\ 1919d02a428SJonas Bonn l.sw PT_GPR7(r1),r7 ;\ 1929d02a428SJonas Bonn l.sw PT_GPR8(r1),r8 ;\ 1939d02a428SJonas Bonn l.sw PT_GPR9(r1),r9 ;\ 1949d02a428SJonas Bonn /* r10 already saved */ ;\ 1959d02a428SJonas Bonn l.sw PT_GPR11(r1),r11 ;\ 1969d02a428SJonas Bonn /* r12 already saved */ ;\ 1979d02a428SJonas Bonn l.sw PT_GPR13(r1),r13 ;\ 1989d02a428SJonas Bonn l.sw PT_GPR14(r1),r14 ;\ 1999d02a428SJonas Bonn l.sw PT_GPR15(r1),r15 ;\ 2009d02a428SJonas Bonn l.sw PT_GPR16(r1),r16 ;\ 2019d02a428SJonas Bonn l.sw PT_GPR17(r1),r17 ;\ 2029d02a428SJonas Bonn l.sw PT_GPR18(r1),r18 ;\ 2039d02a428SJonas Bonn l.sw PT_GPR19(r1),r19 ;\ 2049d02a428SJonas Bonn l.sw PT_GPR20(r1),r20 ;\ 2059d02a428SJonas Bonn l.sw PT_GPR21(r1),r21 ;\ 2069d02a428SJonas Bonn l.sw PT_GPR22(r1),r22 ;\ 2079d02a428SJonas Bonn l.sw PT_GPR23(r1),r23 ;\ 2089d02a428SJonas Bonn l.sw PT_GPR24(r1),r24 ;\ 2099d02a428SJonas Bonn l.sw PT_GPR25(r1),r25 ;\ 2109d02a428SJonas Bonn l.sw PT_GPR26(r1),r26 ;\ 2119d02a428SJonas Bonn l.sw PT_GPR27(r1),r27 ;\ 2129d02a428SJonas Bonn l.sw PT_GPR28(r1),r28 ;\ 2139d02a428SJonas Bonn l.sw PT_GPR29(r1),r29 ;\ 2149d02a428SJonas Bonn /* r31 already saved */ ;\ 2159d02a428SJonas Bonn l.sw PT_GPR30(r1),r30 ;\ 2169d02a428SJonas Bonn/* l.sw PT_GPR31(r1),r31 */ ;\ 2176cbe5e95SJonas Bonn /* Store -1 in orig_gpr11 for non-syscall exceptions */ ;\ 2186cbe5e95SJonas Bonn l.addi r30,r0,-1 ;\ 2196cbe5e95SJonas Bonn l.sw PT_ORIG_GPR11(r1),r30 ;\ 2209d02a428SJonas Bonn l.addi r3,r1,0 ;\ 2219d02a428SJonas Bonn /* r4 is exception EA */ ;\ 2229d02a428SJonas Bonn l.addi r5,r0,vector ;\ 2239d02a428SJonas Bonn l.jal unhandled_exception ;\ 2249d02a428SJonas Bonn l.nop ;\ 2259d02a428SJonas Bonn l.j _ret_from_exception ;\ 2269d02a428SJonas Bonn l.nop 2279d02a428SJonas Bonn 22863104c06SStefan Kristiansson/* clobbers 'reg' */ 22963104c06SStefan Kristiansson#define CLEAR_LWA_FLAG(reg) \ 23063104c06SStefan Kristiansson l.movhi reg,hi(lwa_flag) ;\ 23163104c06SStefan Kristiansson l.ori reg,reg,lo(lwa_flag) ;\ 23263104c06SStefan Kristiansson l.sw 0(reg),r0 2339d02a428SJonas Bonn/* 2349d02a428SJonas Bonn * NOTE: one should never assume that SPR_EPC, SPR_ESR, SPR_EEAR 2359d02a428SJonas Bonn * contain the same values as when exception we're handling 2369d02a428SJonas Bonn * occured. in fact they never do. if you need them use 2379d02a428SJonas Bonn * values saved on stack (for SPR_EPC, SPR_ESR) or content 2389d02a428SJonas Bonn * of r4 (for SPR_EEAR). for details look at EXCEPTION_HANDLE() 23957ce8ba0SGeert Uytterhoeven * in 'arch/openrisc/kernel/head.S' 2409d02a428SJonas Bonn */ 2419d02a428SJonas Bonn 2429d02a428SJonas Bonn/* =====================================================[ exceptions] === */ 2439d02a428SJonas Bonn 2449d02a428SJonas Bonn/* ---[ 0x100: RESET exception ]----------------------------------------- */ 2459d02a428SJonas Bonn 2469d02a428SJonas BonnEXCEPTION_ENTRY(_tng_kernel_start) 2479d02a428SJonas Bonn l.jal _start 2489d02a428SJonas Bonn l.andi r0,r0,0 2499d02a428SJonas Bonn 2509d02a428SJonas Bonn/* ---[ 0x200: BUS exception ]------------------------------------------- */ 2519d02a428SJonas Bonn 2529d02a428SJonas BonnEXCEPTION_ENTRY(_bus_fault_handler) 25363104c06SStefan Kristiansson CLEAR_LWA_FLAG(r3) 2549d02a428SJonas Bonn /* r4: EA of fault (set by EXCEPTION_HANDLE) */ 2559d02a428SJonas Bonn l.jal do_bus_fault 2569d02a428SJonas Bonn l.addi r3,r1,0 /* pt_regs */ 2579d02a428SJonas Bonn 2589d02a428SJonas Bonn l.j _ret_from_exception 2599d02a428SJonas Bonn l.nop 2609d02a428SJonas Bonn 2619d02a428SJonas Bonn/* ---[ 0x300: Data Page Fault exception ]------------------------------- */ 262a81252d7SJonas BonnEXCEPTION_ENTRY(_dtlb_miss_page_fault_handler) 26363104c06SStefan Kristiansson CLEAR_LWA_FLAG(r3) 264a81252d7SJonas Bonn l.and r5,r5,r0 265a81252d7SJonas Bonn l.j 1f 266a81252d7SJonas Bonn l.nop 2679d02a428SJonas Bonn 2689d02a428SJonas BonnEXCEPTION_ENTRY(_data_page_fault_handler) 26963104c06SStefan Kristiansson CLEAR_LWA_FLAG(r3) 2709d02a428SJonas Bonn /* set up parameters for do_page_fault */ 271a81252d7SJonas Bonn l.ori r5,r0,0x300 // exception vector 272a81252d7SJonas Bonn1: 2739d02a428SJonas Bonn l.addi r3,r1,0 // pt_regs 2749d02a428SJonas Bonn /* r4 set be EXCEPTION_HANDLE */ // effective address of fault 2759d02a428SJonas Bonn 2769d02a428SJonas Bonn#ifdef CONFIG_OPENRISC_NO_SPR_SR_DSX 2779d02a428SJonas Bonn l.lwz r6,PT_PC(r3) // address of an offending insn 2789d02a428SJonas Bonn l.lwz r6,0(r6) // instruction that caused pf 2799d02a428SJonas Bonn 2809d02a428SJonas Bonn l.srli r6,r6,26 // check opcode for jump insn 2819d02a428SJonas Bonn l.sfeqi r6,0 // l.j 2829d02a428SJonas Bonn l.bf 8f 2839d02a428SJonas Bonn l.sfeqi r6,1 // l.jal 2849d02a428SJonas Bonn l.bf 8f 2859d02a428SJonas Bonn l.sfeqi r6,3 // l.bnf 2869d02a428SJonas Bonn l.bf 8f 2879d02a428SJonas Bonn l.sfeqi r6,4 // l.bf 2889d02a428SJonas Bonn l.bf 8f 2899d02a428SJonas Bonn l.sfeqi r6,0x11 // l.jr 2909d02a428SJonas Bonn l.bf 8f 2919d02a428SJonas Bonn l.sfeqi r6,0x12 // l.jalr 2929d02a428SJonas Bonn l.bf 8f 2939d02a428SJonas Bonn l.nop 2949d02a428SJonas Bonn 2959d02a428SJonas Bonn l.j 9f 2969d02a428SJonas Bonn l.nop 2979d02a428SJonas Bonn 2982ead7abaSStafford Horne8: // offending insn is in delay slot 2999d02a428SJonas Bonn l.lwz r6,PT_PC(r3) // address of an offending insn 3009d02a428SJonas Bonn l.addi r6,r6,4 3019d02a428SJonas Bonn l.lwz r6,0(r6) // instruction that caused pf 3029d02a428SJonas Bonn l.srli r6,r6,26 // get opcode 3032ead7abaSStafford Horne9: // offending instruction opcode loaded in r6 3049d02a428SJonas Bonn 3059d02a428SJonas Bonn#else 3069d02a428SJonas Bonn 307ae15a41aSStafford Horne l.mfspr r6,r0,SPR_SR // SR 3089d02a428SJonas Bonn l.andi r6,r6,SPR_SR_DSX // check for delay slot exception 309e6d20c55SStafford Horne l.sfne r6,r0 // exception happened in delay slot 3109d02a428SJonas Bonn l.bnf 7f 3119d02a428SJonas Bonn l.lwz r6,PT_PC(r3) // address of an offending insn 3129d02a428SJonas Bonn 3139d02a428SJonas Bonn l.addi r6,r6,4 // offending insn is in delay slot 3149d02a428SJonas Bonn7: 3159d02a428SJonas Bonn l.lwz r6,0(r6) // instruction that caused pf 3169d02a428SJonas Bonn l.srli r6,r6,26 // check opcode for write access 3179d02a428SJonas Bonn#endif 3189d02a428SJonas Bonn 319cdb75442SStefan Kristiansson l.sfgeui r6,0x33 // check opcode for write access 3209d02a428SJonas Bonn l.bnf 1f 3219d02a428SJonas Bonn l.sfleui r6,0x37 3229d02a428SJonas Bonn l.bnf 1f 3239d02a428SJonas Bonn l.ori r6,r0,0x1 // write access 3249d02a428SJonas Bonn l.j 2f 3259d02a428SJonas Bonn l.nop 3269d02a428SJonas Bonn1: l.ori r6,r0,0x0 // !write access 3279d02a428SJonas Bonn2: 3289d02a428SJonas Bonn 32911648cbbSRandy Dunlap /* call fault.c handler in openrisc/mm/fault.c */ 3309d02a428SJonas Bonn l.jal do_page_fault 3319d02a428SJonas Bonn l.nop 3329d02a428SJonas Bonn l.j _ret_from_exception 3339d02a428SJonas Bonn l.nop 3349d02a428SJonas Bonn 3359d02a428SJonas Bonn/* ---[ 0x400: Insn Page Fault exception ]------------------------------- */ 336a81252d7SJonas BonnEXCEPTION_ENTRY(_itlb_miss_page_fault_handler) 33763104c06SStefan Kristiansson CLEAR_LWA_FLAG(r3) 338a81252d7SJonas Bonn l.and r5,r5,r0 339a81252d7SJonas Bonn l.j 1f 340a81252d7SJonas Bonn l.nop 3419d02a428SJonas Bonn 3429d02a428SJonas BonnEXCEPTION_ENTRY(_insn_page_fault_handler) 34363104c06SStefan Kristiansson CLEAR_LWA_FLAG(r3) 3449d02a428SJonas Bonn /* set up parameters for do_page_fault */ 345a81252d7SJonas Bonn l.ori r5,r0,0x400 // exception vector 346a81252d7SJonas Bonn1: 3479d02a428SJonas Bonn l.addi r3,r1,0 // pt_regs 3489d02a428SJonas Bonn /* r4 set be EXCEPTION_HANDLE */ // effective address of fault 3499d02a428SJonas Bonn l.ori r6,r0,0x0 // !write access 3509d02a428SJonas Bonn 35111648cbbSRandy Dunlap /* call fault.c handler in openrisc/mm/fault.c */ 3529d02a428SJonas Bonn l.jal do_page_fault 3539d02a428SJonas Bonn l.nop 3549d02a428SJonas Bonn l.j _ret_from_exception 3559d02a428SJonas Bonn l.nop 3569d02a428SJonas Bonn 3579d02a428SJonas Bonn 3589d02a428SJonas Bonn/* ---[ 0x500: Timer exception ]----------------------------------------- */ 3599d02a428SJonas Bonn 3609d02a428SJonas BonnEXCEPTION_ENTRY(_timer_handler) 36163104c06SStefan Kristiansson CLEAR_LWA_FLAG(r3) 3629d02a428SJonas Bonn l.jal timer_interrupt 3639d02a428SJonas Bonn l.addi r3,r1,0 /* pt_regs */ 3649d02a428SJonas Bonn 3659d02a428SJonas Bonn l.j _ret_from_intr 3669d02a428SJonas Bonn l.nop 3679d02a428SJonas Bonn 368550116d2SMasahiro Yamada/* ---[ 0x600: Alignment exception ]-------------------------------------- */ 3699d02a428SJonas Bonn 3709d02a428SJonas BonnEXCEPTION_ENTRY(_alignment_handler) 37163104c06SStefan Kristiansson CLEAR_LWA_FLAG(r3) 3729d02a428SJonas Bonn /* r4: EA of fault (set by EXCEPTION_HANDLE) */ 3739d02a428SJonas Bonn l.jal do_unaligned_access 3749d02a428SJonas Bonn l.addi r3,r1,0 /* pt_regs */ 3759d02a428SJonas Bonn 3769d02a428SJonas Bonn l.j _ret_from_exception 3779d02a428SJonas Bonn l.nop 3789d02a428SJonas Bonn 3799d02a428SJonas Bonn#if 0 380550116d2SMasahiro YamadaEXCEPTION_ENTRY(_alignment_handler) 3814e0385ddSMasahiro Yamada// l.mfspr r2,r0,SPR_EEAR_BASE /* Load the effective address */ 3829d02a428SJonas Bonn l.addi r2,r4,0 3839d02a428SJonas Bonn// l.mfspr r5,r0,SPR_EPCR_BASE /* Load the insn address */ 3849d02a428SJonas Bonn l.lwz r5,PT_PC(r1) 3859d02a428SJonas Bonn 3869d02a428SJonas Bonn l.lwz r3,0(r5) /* Load insn */ 3879d02a428SJonas Bonn l.srli r4,r3,26 /* Shift left to get the insn opcode */ 3889d02a428SJonas Bonn 3899d02a428SJonas Bonn l.sfeqi r4,0x00 /* Check if the load/store insn is in delay slot */ 3909d02a428SJonas Bonn l.bf jmp 3919d02a428SJonas Bonn l.sfeqi r4,0x01 3929d02a428SJonas Bonn l.bf jmp 3939d02a428SJonas Bonn l.sfeqi r4,0x03 3949d02a428SJonas Bonn l.bf jmp 3959d02a428SJonas Bonn l.sfeqi r4,0x04 3969d02a428SJonas Bonn l.bf jmp 3979d02a428SJonas Bonn l.sfeqi r4,0x11 3989d02a428SJonas Bonn l.bf jr 3999d02a428SJonas Bonn l.sfeqi r4,0x12 4009d02a428SJonas Bonn l.bf jr 4019d02a428SJonas Bonn l.nop 4029d02a428SJonas Bonn l.j 1f 4039d02a428SJonas Bonn l.addi r5,r5,4 /* Increment PC to get return insn address */ 4049d02a428SJonas Bonn 4059d02a428SJonas Bonnjmp: 4069d02a428SJonas Bonn l.slli r4,r3,6 /* Get the signed extended jump length */ 4079d02a428SJonas Bonn l.srai r4,r4,4 4089d02a428SJonas Bonn 4099d02a428SJonas Bonn l.lwz r3,4(r5) /* Load the real load/store insn */ 4109d02a428SJonas Bonn 4119d02a428SJonas Bonn l.add r5,r5,r4 /* Calculate jump target address */ 4129d02a428SJonas Bonn 4139d02a428SJonas Bonn l.j 1f 4149d02a428SJonas Bonn l.srli r4,r3,26 /* Shift left to get the insn opcode */ 4159d02a428SJonas Bonn 4169d02a428SJonas Bonnjr: 4179d02a428SJonas Bonn l.slli r4,r3,9 /* Shift to get the reg nb */ 4189d02a428SJonas Bonn l.andi r4,r4,0x7c 4199d02a428SJonas Bonn 4209d02a428SJonas Bonn l.lwz r3,4(r5) /* Load the real load/store insn */ 4219d02a428SJonas Bonn 4229d02a428SJonas Bonn l.add r4,r4,r1 /* Load the jump register value from the stack */ 4239d02a428SJonas Bonn l.lwz r5,0(r4) 4249d02a428SJonas Bonn 4259d02a428SJonas Bonn l.srli r4,r3,26 /* Shift left to get the insn opcode */ 4269d02a428SJonas Bonn 4279d02a428SJonas Bonn 4289d02a428SJonas Bonn1: 4299d02a428SJonas Bonn// l.mtspr r0,r5,SPR_EPCR_BASE 4309d02a428SJonas Bonn l.sw PT_PC(r1),r5 4319d02a428SJonas Bonn 4329d02a428SJonas Bonn l.sfeqi r4,0x26 4339d02a428SJonas Bonn l.bf lhs 4349d02a428SJonas Bonn l.sfeqi r4,0x25 4359d02a428SJonas Bonn l.bf lhz 4369d02a428SJonas Bonn l.sfeqi r4,0x22 4379d02a428SJonas Bonn l.bf lws 4389d02a428SJonas Bonn l.sfeqi r4,0x21 4399d02a428SJonas Bonn l.bf lwz 4409d02a428SJonas Bonn l.sfeqi r4,0x37 4419d02a428SJonas Bonn l.bf sh 4429d02a428SJonas Bonn l.sfeqi r4,0x35 4439d02a428SJonas Bonn l.bf sw 4449d02a428SJonas Bonn l.nop 4459d02a428SJonas Bonn 4469d02a428SJonas Bonn1: l.j 1b /* I don't know what to do */ 4479d02a428SJonas Bonn l.nop 4489d02a428SJonas Bonn 4499d02a428SJonas Bonnlhs: l.lbs r5,0(r2) 4509d02a428SJonas Bonn l.slli r5,r5,8 4519d02a428SJonas Bonn l.lbz r6,1(r2) 4529d02a428SJonas Bonn l.or r5,r5,r6 4539d02a428SJonas Bonn l.srli r4,r3,19 4549d02a428SJonas Bonn l.andi r4,r4,0x7c 4559d02a428SJonas Bonn l.add r4,r4,r1 4569d02a428SJonas Bonn l.j align_end 4579d02a428SJonas Bonn l.sw 0(r4),r5 4589d02a428SJonas Bonn 4599d02a428SJonas Bonnlhz: l.lbz r5,0(r2) 4609d02a428SJonas Bonn l.slli r5,r5,8 4619d02a428SJonas Bonn l.lbz r6,1(r2) 4629d02a428SJonas Bonn l.or r5,r5,r6 4639d02a428SJonas Bonn l.srli r4,r3,19 4649d02a428SJonas Bonn l.andi r4,r4,0x7c 4659d02a428SJonas Bonn l.add r4,r4,r1 4669d02a428SJonas Bonn l.j align_end 4679d02a428SJonas Bonn l.sw 0(r4),r5 4689d02a428SJonas Bonn 4699d02a428SJonas Bonnlws: l.lbs r5,0(r2) 4709d02a428SJonas Bonn l.slli r5,r5,24 4719d02a428SJonas Bonn l.lbz r6,1(r2) 4729d02a428SJonas Bonn l.slli r6,r6,16 4739d02a428SJonas Bonn l.or r5,r5,r6 4749d02a428SJonas Bonn l.lbz r6,2(r2) 4759d02a428SJonas Bonn l.slli r6,r6,8 4769d02a428SJonas Bonn l.or r5,r5,r6 4779d02a428SJonas Bonn l.lbz r6,3(r2) 4789d02a428SJonas Bonn l.or r5,r5,r6 4799d02a428SJonas Bonn l.srli r4,r3,19 4809d02a428SJonas Bonn l.andi r4,r4,0x7c 4819d02a428SJonas Bonn l.add r4,r4,r1 4829d02a428SJonas Bonn l.j align_end 4839d02a428SJonas Bonn l.sw 0(r4),r5 4849d02a428SJonas Bonn 4859d02a428SJonas Bonnlwz: l.lbz r5,0(r2) 4869d02a428SJonas Bonn l.slli r5,r5,24 4879d02a428SJonas Bonn l.lbz r6,1(r2) 4889d02a428SJonas Bonn l.slli r6,r6,16 4899d02a428SJonas Bonn l.or r5,r5,r6 4909d02a428SJonas Bonn l.lbz r6,2(r2) 4919d02a428SJonas Bonn l.slli r6,r6,8 4929d02a428SJonas Bonn l.or r5,r5,r6 4939d02a428SJonas Bonn l.lbz r6,3(r2) 4949d02a428SJonas Bonn l.or r5,r5,r6 4959d02a428SJonas Bonn l.srli r4,r3,19 4969d02a428SJonas Bonn l.andi r4,r4,0x7c 4979d02a428SJonas Bonn l.add r4,r4,r1 4989d02a428SJonas Bonn l.j align_end 4999d02a428SJonas Bonn l.sw 0(r4),r5 5009d02a428SJonas Bonn 5019d02a428SJonas Bonnsh: 5029d02a428SJonas Bonn l.srli r4,r3,9 5039d02a428SJonas Bonn l.andi r4,r4,0x7c 5049d02a428SJonas Bonn l.add r4,r4,r1 5059d02a428SJonas Bonn l.lwz r5,0(r4) 5069d02a428SJonas Bonn l.sb 1(r2),r5 5079d02a428SJonas Bonn l.srli r5,r5,8 5089d02a428SJonas Bonn l.j align_end 5099d02a428SJonas Bonn l.sb 0(r2),r5 5109d02a428SJonas Bonn 5119d02a428SJonas Bonnsw: 5129d02a428SJonas Bonn l.srli r4,r3,9 5139d02a428SJonas Bonn l.andi r4,r4,0x7c 5149d02a428SJonas Bonn l.add r4,r4,r1 5159d02a428SJonas Bonn l.lwz r5,0(r4) 5169d02a428SJonas Bonn l.sb 3(r2),r5 5179d02a428SJonas Bonn l.srli r5,r5,8 5189d02a428SJonas Bonn l.sb 2(r2),r5 5199d02a428SJonas Bonn l.srli r5,r5,8 5209d02a428SJonas Bonn l.sb 1(r2),r5 5219d02a428SJonas Bonn l.srli r5,r5,8 5229d02a428SJonas Bonn l.j align_end 5239d02a428SJonas Bonn l.sb 0(r2),r5 5249d02a428SJonas Bonn 5259d02a428SJonas Bonnalign_end: 5269d02a428SJonas Bonn l.j _ret_from_intr 5279d02a428SJonas Bonn l.nop 5289d02a428SJonas Bonn#endif 5299d02a428SJonas Bonn 5309d02a428SJonas Bonn/* ---[ 0x700: Illegal insn exception ]---------------------------------- */ 5319d02a428SJonas Bonn 5329d02a428SJonas BonnEXCEPTION_ENTRY(_illegal_instruction_handler) 5339d02a428SJonas Bonn /* r4: EA of fault (set by EXCEPTION_HANDLE) */ 5349d02a428SJonas Bonn l.jal do_illegal_instruction 5359d02a428SJonas Bonn l.addi r3,r1,0 /* pt_regs */ 5369d02a428SJonas Bonn 5379d02a428SJonas Bonn l.j _ret_from_exception 5389d02a428SJonas Bonn l.nop 5399d02a428SJonas Bonn 5409d02a428SJonas Bonn/* ---[ 0x800: External interrupt exception ]---------------------------- */ 5419d02a428SJonas Bonn 5429d02a428SJonas BonnEXCEPTION_ENTRY(_external_irq_handler) 5439d02a428SJonas Bonn#ifdef CONFIG_OPENRISC_ESR_EXCEPTION_BUG_CHECK 5449d02a428SJonas Bonn l.lwz r4,PT_SR(r1) // were interrupts enabled ? 5459d02a428SJonas Bonn l.andi r4,r4,SPR_SR_IEE 5469d02a428SJonas Bonn l.sfeqi r4,0 5479d02a428SJonas Bonn l.bnf 1f // ext irq enabled, all ok. 5489d02a428SJonas Bonn l.nop 5499d02a428SJonas Bonn 550946e1052SRandy Dunlap#ifdef CONFIG_PRINTK 5519d02a428SJonas Bonn l.addi r1,r1,-0x8 5529d02a428SJonas Bonn l.movhi r3,hi(42f) 5539d02a428SJonas Bonn l.ori r3,r3,lo(42f) 5549d02a428SJonas Bonn l.sw 0x0(r1),r3 55533701557SChris Down l.jal _printk 5569d02a428SJonas Bonn l.sw 0x4(r1),r4 5579d02a428SJonas Bonn l.addi r1,r1,0x8 5589d02a428SJonas Bonn 5599d02a428SJonas Bonn .section .rodata, "a" 5609d02a428SJonas Bonn42: 5619d02a428SJonas Bonn .string "\n\rESR interrupt bug: in _external_irq_handler (ESR %x)\n\r" 5629d02a428SJonas Bonn .align 4 5639d02a428SJonas Bonn .previous 564946e1052SRandy Dunlap#endif 5659d02a428SJonas Bonn 5669d02a428SJonas Bonn l.ori r4,r4,SPR_SR_IEE // fix the bug 5679d02a428SJonas Bonn// l.sw PT_SR(r1),r4 5689d02a428SJonas Bonn1: 5699d02a428SJonas Bonn#endif 57063104c06SStefan Kristiansson CLEAR_LWA_FLAG(r3) 5719d02a428SJonas Bonn l.addi r3,r1,0 572418360b2SMark Rutland l.movhi r8,hi(generic_handle_arch_irq) 573418360b2SMark Rutland l.ori r8,r8,lo(generic_handle_arch_irq) 5749d02a428SJonas Bonn l.jalr r8 5759d02a428SJonas Bonn l.nop 5769d02a428SJonas Bonn l.j _ret_from_intr 5779d02a428SJonas Bonn l.nop 5789d02a428SJonas Bonn 5799d02a428SJonas Bonn/* ---[ 0x900: DTLB miss exception ]------------------------------------- */ 5809d02a428SJonas Bonn 5819d02a428SJonas Bonn 5829d02a428SJonas Bonn/* ---[ 0xa00: ITLB miss exception ]------------------------------------- */ 5839d02a428SJonas Bonn 5849d02a428SJonas Bonn 5859d02a428SJonas Bonn/* ---[ 0xb00: Range exception ]----------------------------------------- */ 5869d02a428SJonas Bonn 5879d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0xb00,0xb00) 5889d02a428SJonas Bonn 5899d02a428SJonas Bonn/* ---[ 0xc00: Syscall exception ]--------------------------------------- */ 5909d02a428SJonas Bonn 5919d02a428SJonas Bonn/* 5929d02a428SJonas Bonn * Syscalls are a special type of exception in that they are 5939d02a428SJonas Bonn * _explicitly_ invoked by userspace and can therefore be 5949d02a428SJonas Bonn * held to conform to the same ABI as normal functions with 5959d02a428SJonas Bonn * respect to whether registers are preserved across the call 5969d02a428SJonas Bonn * or not. 5979d02a428SJonas Bonn */ 5989d02a428SJonas Bonn 5999d02a428SJonas Bonn/* Upon syscall entry we just save the callee-saved registers 6009d02a428SJonas Bonn * and not the call-clobbered ones. 6019d02a428SJonas Bonn */ 6029d02a428SJonas Bonn 6039d02a428SJonas Bonn_string_syscall_return: 6049d02a428SJonas Bonn .string "syscall return %ld \n\r\0" 6059d02a428SJonas Bonn .align 4 6069d02a428SJonas Bonn 6079d02a428SJonas BonnENTRY(_sys_call_handler) 6089d02a428SJonas Bonn /* r1, EPCR, ESR a already saved */ 6099d02a428SJonas Bonn l.sw PT_GPR2(r1),r2 6109d02a428SJonas Bonn /* r3-r8 must be saved because syscall restart relies 6119d02a428SJonas Bonn * on us being able to restart the syscall args... technically 6129d02a428SJonas Bonn * they should be clobbered, otherwise 6139d02a428SJonas Bonn */ 6149d02a428SJonas Bonn l.sw PT_GPR3(r1),r3 61563104c06SStefan Kristiansson /* 61663104c06SStefan Kristiansson * r4 already saved 61763104c06SStefan Kristiansson * r4 holds the EEAR address of the fault, use it as screatch reg and 61863104c06SStefan Kristiansson * then load the original r4 61963104c06SStefan Kristiansson */ 62063104c06SStefan Kristiansson CLEAR_LWA_FLAG(r4) 6219d02a428SJonas Bonn l.lwz r4,PT_GPR4(r1) 6229d02a428SJonas Bonn l.sw PT_GPR5(r1),r5 6239d02a428SJonas Bonn l.sw PT_GPR6(r1),r6 6249d02a428SJonas Bonn l.sw PT_GPR7(r1),r7 6259d02a428SJonas Bonn l.sw PT_GPR8(r1),r8 6269d02a428SJonas Bonn l.sw PT_GPR9(r1),r9 6279d02a428SJonas Bonn /* r10 already saved */ 6289d02a428SJonas Bonn l.sw PT_GPR11(r1),r11 6296cbe5e95SJonas Bonn /* orig_gpr11 must be set for syscalls */ 6309d02a428SJonas Bonn l.sw PT_ORIG_GPR11(r1),r11 6319d02a428SJonas Bonn /* r12,r13 already saved */ 6329d02a428SJonas Bonn 6339d02a428SJonas Bonn /* r14-r28 (even) aren't touched by the syscall fast path below 6349d02a428SJonas Bonn * so we don't need to save them. However, the functions that return 6359d02a428SJonas Bonn * to userspace via a call to switch() DO need to save these because 6369d02a428SJonas Bonn * switch() effectively clobbers them... saving these registers for 6379d02a428SJonas Bonn * such functions is handled in their syscall wrappers (see fork, vfork, 6389d02a428SJonas Bonn * and clone, below). 6399d02a428SJonas Bonn 6409d02a428SJonas Bonn /* r30 is the only register we clobber in the fast path */ 6419d02a428SJonas Bonn /* r30 already saved */ 6429d02a428SJonas Bonn/* l.sw PT_GPR30(r1),r30 */ 6439d02a428SJonas Bonn 6449d02a428SJonas Bonn_syscall_check_trace_enter: 64578cdfb5cSStafford Horne /* syscalls run with interrupts enabled */ 64678cdfb5cSStafford Horne TRACE_IRQS_ON_SYSCALL 64778cdfb5cSStafford Horne ENABLE_INTERRUPTS(r29) // enable interrupts, r29 is temp 64878cdfb5cSStafford Horne 6499d02a428SJonas Bonn /* If TIF_SYSCALL_TRACE is set, then we want to do syscall tracing */ 6509d02a428SJonas Bonn l.lwz r30,TI_FLAGS(r10) 6519d02a428SJonas Bonn l.andi r30,r30,_TIF_SYSCALL_TRACE 6529d02a428SJonas Bonn l.sfne r30,r0 6539d02a428SJonas Bonn l.bf _syscall_trace_enter 6549d02a428SJonas Bonn l.nop 6559d02a428SJonas Bonn 6569d02a428SJonas Bonn_syscall_check: 6579d02a428SJonas Bonn /* Ensure that the syscall number is reasonable */ 6589d02a428SJonas Bonn l.sfgeui r11,__NR_syscalls 6599d02a428SJonas Bonn l.bf _syscall_badsys 6609d02a428SJonas Bonn l.nop 6619d02a428SJonas Bonn 6629d02a428SJonas Bonn_syscall_call: 6639d02a428SJonas Bonn l.movhi r29,hi(sys_call_table) 6649d02a428SJonas Bonn l.ori r29,r29,lo(sys_call_table) 6659d02a428SJonas Bonn l.slli r11,r11,2 6669d02a428SJonas Bonn l.add r29,r29,r11 6679d02a428SJonas Bonn l.lwz r29,0(r29) 6689d02a428SJonas Bonn 6699d02a428SJonas Bonn l.jalr r29 6709d02a428SJonas Bonn l.nop 6719d02a428SJonas Bonn 6729d02a428SJonas Bonn_syscall_return: 6739d02a428SJonas Bonn /* All syscalls return here... just pay attention to ret_from_fork 6749d02a428SJonas Bonn * which does it in a round-about way. 6759d02a428SJonas Bonn */ 6769d02a428SJonas Bonn l.sw PT_GPR11(r1),r11 // save return value 6779d02a428SJonas Bonn 6789d02a428SJonas Bonn#if 0 6799d02a428SJonas Bonn_syscall_debug: 6809d02a428SJonas Bonn l.movhi r3,hi(_string_syscall_return) 6819d02a428SJonas Bonn l.ori r3,r3,lo(_string_syscall_return) 6829d02a428SJonas Bonn l.ori r27,r0,1 6839d02a428SJonas Bonn l.sw -4(r1),r27 6849d02a428SJonas Bonn l.sw -8(r1),r11 6859d02a428SJonas Bonn l.addi r1,r1,-8 68633701557SChris Down l.movhi r27,hi(_printk) 68733701557SChris Down l.ori r27,r27,lo(_printk) 6889d02a428SJonas Bonn l.jalr r27 6899d02a428SJonas Bonn l.nop 6909d02a428SJonas Bonn l.addi r1,r1,8 6919d02a428SJonas Bonn#endif 6929d02a428SJonas Bonn 6939d02a428SJonas Bonn_syscall_check_trace_leave: 6949d02a428SJonas Bonn /* r30 is a callee-saved register so this should still hold the 6959d02a428SJonas Bonn * _TIF_SYSCALL_TRACE flag from _syscall_check_trace_enter above... 6969d02a428SJonas Bonn * _syscall_trace_leave expects syscall result to be in pt_regs->r11. 6979d02a428SJonas Bonn */ 6989d02a428SJonas Bonn l.sfne r30,r0 6999d02a428SJonas Bonn l.bf _syscall_trace_leave 7009d02a428SJonas Bonn l.nop 7019d02a428SJonas Bonn 7029d02a428SJonas Bonn/* This is where the exception-return code begins... interrupts need to be 7039d02a428SJonas Bonn * disabled the rest of the way here because we can't afford to miss any 7049d02a428SJonas Bonn * interrupts that set NEED_RESCHED or SIGNALPENDING... really true? */ 7059d02a428SJonas Bonn 7069d02a428SJonas Bonn_syscall_check_work: 7079d02a428SJonas Bonn /* Here we need to disable interrupts */ 7089d02a428SJonas Bonn DISABLE_INTERRUPTS(r27,r29) 70978cdfb5cSStafford Horne TRACE_IRQS_OFF 7109d02a428SJonas Bonn l.lwz r30,TI_FLAGS(r10) 7119d02a428SJonas Bonn l.andi r30,r30,_TIF_WORK_MASK 7129d02a428SJonas Bonn l.sfne r30,r0 7139d02a428SJonas Bonn 7149d02a428SJonas Bonn l.bnf _syscall_resume_userspace 7159d02a428SJonas Bonn l.nop 7169d02a428SJonas Bonn 7179d02a428SJonas Bonn /* Work pending follows a different return path, so we need to 7189d02a428SJonas Bonn * make sure that all the call-saved registers get into pt_regs 7199d02a428SJonas Bonn * before branching... 7209d02a428SJonas Bonn */ 7219d02a428SJonas Bonn l.sw PT_GPR14(r1),r14 7229d02a428SJonas Bonn l.sw PT_GPR16(r1),r16 7239d02a428SJonas Bonn l.sw PT_GPR18(r1),r18 7249d02a428SJonas Bonn l.sw PT_GPR20(r1),r20 7259d02a428SJonas Bonn l.sw PT_GPR22(r1),r22 7269d02a428SJonas Bonn l.sw PT_GPR24(r1),r24 7279d02a428SJonas Bonn l.sw PT_GPR26(r1),r26 7289d02a428SJonas Bonn l.sw PT_GPR28(r1),r28 7299d02a428SJonas Bonn 7309d02a428SJonas Bonn /* _work_pending needs to be called with interrupts disabled */ 7319d02a428SJonas Bonn l.j _work_pending 7329d02a428SJonas Bonn l.nop 7339d02a428SJonas Bonn 7349d02a428SJonas Bonn_syscall_resume_userspace: 7359d02a428SJonas Bonn// ENABLE_INTERRUPTS(r29) 7369d02a428SJonas Bonn 7379d02a428SJonas Bonn 7389d02a428SJonas Bonn/* This is the hot path for returning to userspace from a syscall. If there's 7399d02a428SJonas Bonn * work to be done and the branch to _work_pending was taken above, then the 7409d02a428SJonas Bonn * return to userspace will be done via the normal exception return path... 7419d02a428SJonas Bonn * that path restores _all_ registers and will overwrite the "clobbered" 7429d02a428SJonas Bonn * registers with whatever garbage is in pt_regs -- that's OK because those 7439d02a428SJonas Bonn * registers are clobbered anyway and because the extra work is insignificant 7449d02a428SJonas Bonn * in the context of the extra work that _work_pending is doing. 7459d02a428SJonas Bonn 7469d02a428SJonas Bonn/* Once again, syscalls are special and only guarantee to preserve the 7479d02a428SJonas Bonn * same registers as a normal function call */ 7489d02a428SJonas Bonn 7499d02a428SJonas Bonn/* The assumption here is that the registers r14-r28 (even) are untouched and 7509d02a428SJonas Bonn * don't need to be restored... be sure that that's really the case! 7519d02a428SJonas Bonn */ 7529d02a428SJonas Bonn 7539d02a428SJonas Bonn/* This is still too much... we should only be restoring what we actually 7549d02a428SJonas Bonn * clobbered... we should even be using 'scratch' (odd) regs above so that 7559d02a428SJonas Bonn * we don't need to restore anything, hardly... 7569d02a428SJonas Bonn */ 7579d02a428SJonas Bonn 7589d02a428SJonas Bonn l.lwz r2,PT_GPR2(r1) 7599d02a428SJonas Bonn 7609d02a428SJonas Bonn /* Restore args */ 7619d02a428SJonas Bonn /* r3-r8 are technically clobbered, but syscall restart needs these 7629d02a428SJonas Bonn * to be restored... 7639d02a428SJonas Bonn */ 7649d02a428SJonas Bonn l.lwz r3,PT_GPR3(r1) 7659d02a428SJonas Bonn l.lwz r4,PT_GPR4(r1) 7669d02a428SJonas Bonn l.lwz r5,PT_GPR5(r1) 7679d02a428SJonas Bonn l.lwz r6,PT_GPR6(r1) 7689d02a428SJonas Bonn l.lwz r7,PT_GPR7(r1) 7699d02a428SJonas Bonn l.lwz r8,PT_GPR8(r1) 7709d02a428SJonas Bonn 7719d02a428SJonas Bonn l.lwz r9,PT_GPR9(r1) 7729d02a428SJonas Bonn l.lwz r10,PT_GPR10(r1) 7739d02a428SJonas Bonn l.lwz r11,PT_GPR11(r1) 7749d02a428SJonas Bonn 7759d02a428SJonas Bonn /* r30 is the only register we clobber in the fast path */ 7769d02a428SJonas Bonn l.lwz r30,PT_GPR30(r1) 7779d02a428SJonas Bonn 7789d02a428SJonas Bonn /* Here we use r13-r19 (odd) as scratch regs */ 7799d02a428SJonas Bonn l.lwz r13,PT_PC(r1) 7809d02a428SJonas Bonn l.lwz r15,PT_SR(r1) 7819d02a428SJonas Bonn l.lwz r1,PT_SP(r1) 7829d02a428SJonas Bonn /* Interrupts need to be disabled for setting EPCR and ESR 7839d02a428SJonas Bonn * so that another interrupt doesn't come in here and clobber 7849d02a428SJonas Bonn * them before we can use them for our l.rfe */ 7859d02a428SJonas Bonn DISABLE_INTERRUPTS(r17,r19) 7869d02a428SJonas Bonn l.mtspr r0,r13,SPR_EPCR_BASE 7879d02a428SJonas Bonn l.mtspr r0,r15,SPR_ESR_BASE 7889d02a428SJonas Bonn l.rfe 7899d02a428SJonas Bonn 7909d02a428SJonas Bonn/* End of hot path! 7919d02a428SJonas Bonn * Keep the below tracing and error handling out of the hot path... 7929d02a428SJonas Bonn*/ 7939d02a428SJonas Bonn 7949d02a428SJonas Bonn_syscall_trace_enter: 7959d02a428SJonas Bonn /* Here we pass pt_regs to do_syscall_trace_enter. Make sure 7969d02a428SJonas Bonn * that function is really getting all the info it needs as 7979d02a428SJonas Bonn * pt_regs isn't a complete set of userspace regs, just the 7989d02a428SJonas Bonn * ones relevant to the syscall... 7999d02a428SJonas Bonn * 8009d02a428SJonas Bonn * Note use of delay slot for setting argument. 8019d02a428SJonas Bonn */ 8029d02a428SJonas Bonn l.jal do_syscall_trace_enter 8039d02a428SJonas Bonn l.addi r3,r1,0 8049d02a428SJonas Bonn 8059d02a428SJonas Bonn /* Restore arguments (not preserved across do_syscall_trace_enter) 8069d02a428SJonas Bonn * so that we can do the syscall for real and return to the syscall 8079d02a428SJonas Bonn * hot path. 8089d02a428SJonas Bonn */ 8096cbe5e95SJonas Bonn l.lwz r11,PT_GPR11(r1) 8109d02a428SJonas Bonn l.lwz r3,PT_GPR3(r1) 8119d02a428SJonas Bonn l.lwz r4,PT_GPR4(r1) 8129d02a428SJonas Bonn l.lwz r5,PT_GPR5(r1) 8139d02a428SJonas Bonn l.lwz r6,PT_GPR6(r1) 8149d02a428SJonas Bonn l.lwz r7,PT_GPR7(r1) 8159d02a428SJonas Bonn 8169d02a428SJonas Bonn l.j _syscall_check 8179d02a428SJonas Bonn l.lwz r8,PT_GPR8(r1) 8189d02a428SJonas Bonn 8199d02a428SJonas Bonn_syscall_trace_leave: 8209d02a428SJonas Bonn l.jal do_syscall_trace_leave 8219d02a428SJonas Bonn l.addi r3,r1,0 8229d02a428SJonas Bonn 8239d02a428SJonas Bonn l.j _syscall_check_work 8249d02a428SJonas Bonn l.nop 8259d02a428SJonas Bonn 8269d02a428SJonas Bonn_syscall_badsys: 8279d02a428SJonas Bonn /* Here we effectively pretend to have executed an imaginary 8289d02a428SJonas Bonn * syscall that returns -ENOSYS and then return to the regular 8299d02a428SJonas Bonn * syscall hot path. 8309d02a428SJonas Bonn * Note that "return value" is set in the delay slot... 8319d02a428SJonas Bonn */ 8329d02a428SJonas Bonn l.j _syscall_return 8339d02a428SJonas Bonn l.addi r11,r0,-ENOSYS 8349d02a428SJonas Bonn 8359d02a428SJonas Bonn/******* END SYSCALL HANDLING *******/ 8369d02a428SJonas Bonn 8379d02a428SJonas Bonn/* ---[ 0xd00: Trap exception ]------------------------------------------ */ 8389d02a428SJonas Bonn 8399d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0xd00,0xd00) 8409d02a428SJonas Bonn 8419d02a428SJonas Bonn/* ---[ 0xe00: Trap exception ]------------------------------------------ */ 8429d02a428SJonas Bonn 8439d02a428SJonas BonnEXCEPTION_ENTRY(_trap_handler) 84463104c06SStefan Kristiansson CLEAR_LWA_FLAG(r3) 8459d02a428SJonas Bonn /* r4: EA of fault (set by EXCEPTION_HANDLE) */ 8469d02a428SJonas Bonn l.jal do_trap 8479d02a428SJonas Bonn l.addi r3,r1,0 /* pt_regs */ 8489d02a428SJonas Bonn 8499d02a428SJonas Bonn l.j _ret_from_exception 8509d02a428SJonas Bonn l.nop 8519d02a428SJonas Bonn 8529d02a428SJonas Bonn/* ---[ 0xf00: Reserved exception ]-------------------------------------- */ 8539d02a428SJonas Bonn 8549d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0xf00,0xf00) 8559d02a428SJonas Bonn 8569d02a428SJonas Bonn/* ---[ 0x1000: Reserved exception ]------------------------------------- */ 8579d02a428SJonas Bonn 8589d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1000,0x1000) 8599d02a428SJonas Bonn 8609d02a428SJonas Bonn/* ---[ 0x1100: Reserved exception ]------------------------------------- */ 8619d02a428SJonas Bonn 8629d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1100,0x1100) 8639d02a428SJonas Bonn 8649d02a428SJonas Bonn/* ---[ 0x1200: Reserved exception ]------------------------------------- */ 8659d02a428SJonas Bonn 8669d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1200,0x1200) 8679d02a428SJonas Bonn 8689d02a428SJonas Bonn/* ---[ 0x1300: Reserved exception ]------------------------------------- */ 8699d02a428SJonas Bonn 8709d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1300,0x1300) 8719d02a428SJonas Bonn 8729d02a428SJonas Bonn/* ---[ 0x1400: Reserved exception ]------------------------------------- */ 8739d02a428SJonas Bonn 8749d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1400,0x1400) 8759d02a428SJonas Bonn 8769d02a428SJonas Bonn/* ---[ 0x1500: Reserved exception ]------------------------------------- */ 8779d02a428SJonas Bonn 8789d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1500,0x1500) 8799d02a428SJonas Bonn 8809d02a428SJonas Bonn/* ---[ 0x1600: Reserved exception ]------------------------------------- */ 8819d02a428SJonas Bonn 8829d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1600,0x1600) 8839d02a428SJonas Bonn 8849d02a428SJonas Bonn/* ---[ 0x1700: Reserved exception ]------------------------------------- */ 8859d02a428SJonas Bonn 8869d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1700,0x1700) 8879d02a428SJonas Bonn 8889d02a428SJonas Bonn/* ---[ 0x1800: Reserved exception ]------------------------------------- */ 8899d02a428SJonas Bonn 8909d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1800,0x1800) 8919d02a428SJonas Bonn 8929d02a428SJonas Bonn/* ---[ 0x1900: Reserved exception ]------------------------------------- */ 8939d02a428SJonas Bonn 8949d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1900,0x1900) 8959d02a428SJonas Bonn 8969d02a428SJonas Bonn/* ---[ 0x1a00: Reserved exception ]------------------------------------- */ 8979d02a428SJonas Bonn 8989d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1a00,0x1a00) 8999d02a428SJonas Bonn 9009d02a428SJonas Bonn/* ---[ 0x1b00: Reserved exception ]------------------------------------- */ 9019d02a428SJonas Bonn 9029d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1b00,0x1b00) 9039d02a428SJonas Bonn 9049d02a428SJonas Bonn/* ---[ 0x1c00: Reserved exception ]------------------------------------- */ 9059d02a428SJonas Bonn 9069d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1c00,0x1c00) 9079d02a428SJonas Bonn 9089d02a428SJonas Bonn/* ---[ 0x1d00: Reserved exception ]------------------------------------- */ 9099d02a428SJonas Bonn 9109d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1d00,0x1d00) 9119d02a428SJonas Bonn 9129d02a428SJonas Bonn/* ---[ 0x1e00: Reserved exception ]------------------------------------- */ 9139d02a428SJonas Bonn 9149d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1e00,0x1e00) 9159d02a428SJonas Bonn 9169d02a428SJonas Bonn/* ---[ 0x1f00: Reserved exception ]------------------------------------- */ 9179d02a428SJonas Bonn 9189d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1f00,0x1f00) 9199d02a428SJonas Bonn 9209d02a428SJonas Bonn/* ========================================================[ return ] === */ 9219d02a428SJonas Bonn 9229d02a428SJonas Bonn_resume_userspace: 9239d02a428SJonas Bonn DISABLE_INTERRUPTS(r3,r4) 92478cdfb5cSStafford Horne TRACE_IRQS_OFF 92510f67dbfSJonas Bonn l.lwz r4,TI_FLAGS(r10) 92610f67dbfSJonas Bonn l.andi r13,r4,_TIF_WORK_MASK 92710f67dbfSJonas Bonn l.sfeqi r13,0 92810f67dbfSJonas Bonn l.bf _restore_all 9299d02a428SJonas Bonn l.nop 9309d02a428SJonas Bonn 93110f67dbfSJonas Bonn_work_pending: 93210f67dbfSJonas Bonn l.lwz r5,PT_ORIG_GPR11(r1) 93310f67dbfSJonas Bonn l.sfltsi r5,0 93410f67dbfSJonas Bonn l.bnf 1f 93510f67dbfSJonas Bonn l.nop 93610f67dbfSJonas Bonn l.andi r5,r5,0 93710f67dbfSJonas Bonn1: 93810f67dbfSJonas Bonn l.jal do_work_pending 93910f67dbfSJonas Bonn l.ori r3,r1,0 /* pt_regs */ 94010f67dbfSJonas Bonn 94110f67dbfSJonas Bonn l.sfeqi r11,0 94210f67dbfSJonas Bonn l.bf _restore_all 94310f67dbfSJonas Bonn l.nop 94410f67dbfSJonas Bonn l.sfltsi r11,0 94510f67dbfSJonas Bonn l.bnf 1f 94610f67dbfSJonas Bonn l.nop 94710f67dbfSJonas Bonn l.and r11,r11,r0 94810f67dbfSJonas Bonn l.ori r11,r11,__NR_restart_syscall 94910f67dbfSJonas Bonn l.j _syscall_check_trace_enter 95010f67dbfSJonas Bonn l.nop 95110f67dbfSJonas Bonn1: 95210f67dbfSJonas Bonn l.lwz r11,PT_ORIG_GPR11(r1) 95310f67dbfSJonas Bonn /* Restore arg registers */ 95410f67dbfSJonas Bonn l.lwz r3,PT_GPR3(r1) 95510f67dbfSJonas Bonn l.lwz r4,PT_GPR4(r1) 95610f67dbfSJonas Bonn l.lwz r5,PT_GPR5(r1) 95710f67dbfSJonas Bonn l.lwz r6,PT_GPR6(r1) 95810f67dbfSJonas Bonn l.lwz r7,PT_GPR7(r1) 95910f67dbfSJonas Bonn l.j _syscall_check_trace_enter 96010f67dbfSJonas Bonn l.lwz r8,PT_GPR8(r1) 96110f67dbfSJonas Bonn 9629d02a428SJonas Bonn_restore_all: 96378cdfb5cSStafford Horne#ifdef CONFIG_TRACE_IRQFLAGS 96478cdfb5cSStafford Horne l.lwz r4,PT_SR(r1) 96578cdfb5cSStafford Horne l.andi r3,r4,(SPR_SR_IEE|SPR_SR_TEE) 96678cdfb5cSStafford Horne l.sfeq r3,r0 /* skip trace if irqs were off */ 96778cdfb5cSStafford Horne l.bf skip_hardirqs_on 96878cdfb5cSStafford Horne l.nop 96978cdfb5cSStafford Horne TRACE_IRQS_ON 97078cdfb5cSStafford Horneskip_hardirqs_on: 97178cdfb5cSStafford Horne#endif 9729d02a428SJonas Bonn RESTORE_ALL 9739d02a428SJonas Bonn /* This returns to userspace code */ 9749d02a428SJonas Bonn 9759d02a428SJonas Bonn 9769d02a428SJonas BonnENTRY(_ret_from_intr) 9779d02a428SJonas BonnENTRY(_ret_from_exception) 9789d02a428SJonas Bonn l.lwz r4,PT_SR(r1) 9799d02a428SJonas Bonn l.andi r3,r4,SPR_SR_SM 9809d02a428SJonas Bonn l.sfeqi r3,0 9819d02a428SJonas Bonn l.bnf _restore_all 9829d02a428SJonas Bonn l.nop 9839d02a428SJonas Bonn l.j _resume_userspace 9849d02a428SJonas Bonn l.nop 9859d02a428SJonas Bonn 9869d02a428SJonas BonnENTRY(ret_from_fork) 9879d02a428SJonas Bonn l.jal schedule_tail 9889d02a428SJonas Bonn l.nop 9899d02a428SJonas Bonn 990cbf23cf1SJonas Bonn /* Check if we are a kernel thread */ 991cbf23cf1SJonas Bonn l.sfeqi r20,0 992cbf23cf1SJonas Bonn l.bf 1f 993cbf23cf1SJonas Bonn l.nop 994cbf23cf1SJonas Bonn 995cbf23cf1SJonas Bonn /* ...we are a kernel thread so invoke the requested callback */ 996cbf23cf1SJonas Bonn l.jalr r20 997cbf23cf1SJonas Bonn l.or r3,r22,r0 998cbf23cf1SJonas Bonn 999cbf23cf1SJonas Bonn1: 10009d02a428SJonas Bonn /* _syscall_returns expect r11 to contain return value */ 10019d02a428SJonas Bonn l.lwz r11,PT_GPR11(r1) 10029d02a428SJonas Bonn 10039d02a428SJonas Bonn /* The syscall fast path return expects call-saved registers 1004840b66c2SStafford Horne * r14-r28 to be untouched, so we restore them here as they 10059d02a428SJonas Bonn * will have been effectively clobbered when arriving here 10069d02a428SJonas Bonn * via the call to switch() 10079d02a428SJonas Bonn */ 10089d02a428SJonas Bonn l.lwz r14,PT_GPR14(r1) 10099d02a428SJonas Bonn l.lwz r16,PT_GPR16(r1) 10109d02a428SJonas Bonn l.lwz r18,PT_GPR18(r1) 10119d02a428SJonas Bonn l.lwz r20,PT_GPR20(r1) 10129d02a428SJonas Bonn l.lwz r22,PT_GPR22(r1) 10139d02a428SJonas Bonn l.lwz r24,PT_GPR24(r1) 10149d02a428SJonas Bonn l.lwz r26,PT_GPR26(r1) 10159d02a428SJonas Bonn l.lwz r28,PT_GPR28(r1) 10169d02a428SJonas Bonn 10179d02a428SJonas Bonn l.j _syscall_return 10189d02a428SJonas Bonn l.nop 10199d02a428SJonas Bonn 10209d02a428SJonas Bonn/* ========================================================[ switch ] === */ 10219d02a428SJonas Bonn 10229d02a428SJonas Bonn/* 10239d02a428SJonas Bonn * This routine switches between two different tasks. The process 10249d02a428SJonas Bonn * state of one is saved on its kernel stack. Then the state 10259d02a428SJonas Bonn * of the other is restored from its kernel stack. The memory 10269d02a428SJonas Bonn * management hardware is updated to the second process's state. 10279d02a428SJonas Bonn * Finally, we can return to the second process, via the 'return'. 10289d02a428SJonas Bonn * 10299d02a428SJonas Bonn * Note: there are two ways to get to the "going out" portion 10309d02a428SJonas Bonn * of this code; either by coming in via the entry (_switch) 10319d02a428SJonas Bonn * or via "fork" which must set up an environment equivalent 10329d02a428SJonas Bonn * to the "_switch" path. If you change this (or in particular, the 10339d02a428SJonas Bonn * SAVE_REGS macro), you'll have to change the fork code also. 10349d02a428SJonas Bonn */ 10359d02a428SJonas Bonn 10369d02a428SJonas Bonn 10379d02a428SJonas Bonn/* _switch MUST never lay on page boundry, cause it runs from 10389d02a428SJonas Bonn * effective addresses and beeing interrupted by iTLB miss would kill it. 1039840b66c2SStafford Horne * dTLB miss seems to never accour in the bad place since data accesses 10409d02a428SJonas Bonn * are from task structures which are always page aligned. 10419d02a428SJonas Bonn * 1042840b66c2SStafford Horne * The problem happens in RESTORE_ALL where we first set the EPCR 10439d02a428SJonas Bonn * register, then load the previous register values and only at the end call 10449d02a428SJonas Bonn * the l.rfe instruction. If get TLB miss in beetwen the EPCR register gets 10459d02a428SJonas Bonn * garbled and we end up calling l.rfe with the wrong EPCR. (same probably 10469d02a428SJonas Bonn * holds for ESR) 10479d02a428SJonas Bonn * 10489d02a428SJonas Bonn * To avoid this problems it is sufficient to align _switch to 10499d02a428SJonas Bonn * some nice round number smaller than it's size... 10509d02a428SJonas Bonn */ 10519d02a428SJonas Bonn 10529d02a428SJonas Bonn/* ABI rules apply here... we either enter _switch via schedule() or via 10539d02a428SJonas Bonn * an imaginary call to which we shall return at return_from_fork. Either 10549d02a428SJonas Bonn * way, we are a function call and only need to preserve the callee-saved 10559d02a428SJonas Bonn * registers when we return. As such, we don't need to save the registers 10569d02a428SJonas Bonn * on the stack that we won't be returning as they were... 10579d02a428SJonas Bonn */ 10589d02a428SJonas Bonn 10599d02a428SJonas Bonn .align 0x400 10609d02a428SJonas BonnENTRY(_switch) 10619d02a428SJonas Bonn /* We don't store SR as _switch only gets called in a context where 10629d02a428SJonas Bonn * the SR will be the same going in and coming out... */ 10639d02a428SJonas Bonn 10649d02a428SJonas Bonn /* Set up new pt_regs struct for saving task state */ 10659d02a428SJonas Bonn l.addi r1,r1,-(INT_FRAME_SIZE) 10669d02a428SJonas Bonn 10679d02a428SJonas Bonn /* No need to store r1/PT_SP as it goes into KSP below */ 10689d02a428SJonas Bonn l.sw PT_GPR2(r1),r2 10699d02a428SJonas Bonn l.sw PT_GPR9(r1),r9 1070840b66c2SStafford Horne 1071840b66c2SStafford Horne /* Save callee-saved registers to the new pt_regs */ 10729d02a428SJonas Bonn l.sw PT_GPR14(r1),r14 10739d02a428SJonas Bonn l.sw PT_GPR16(r1),r16 10749d02a428SJonas Bonn l.sw PT_GPR18(r1),r18 10759d02a428SJonas Bonn l.sw PT_GPR20(r1),r20 10769d02a428SJonas Bonn l.sw PT_GPR22(r1),r22 10779d02a428SJonas Bonn l.sw PT_GPR24(r1),r24 10789d02a428SJonas Bonn l.sw PT_GPR26(r1),r26 10799d02a428SJonas Bonn l.sw PT_GPR28(r1),r28 10809d02a428SJonas Bonn l.sw PT_GPR30(r1),r30 10819d02a428SJonas Bonn 10829d02a428SJonas Bonn l.addi r11,r10,0 /* Save old 'current' to 'last' return value*/ 10839d02a428SJonas Bonn 10849d02a428SJonas Bonn /* We use thread_info->ksp for storing the address of the above 10859d02a428SJonas Bonn * structure so that we can get back to it later... we don't want 10869d02a428SJonas Bonn * to lose the value of thread_info->ksp, though, so store it as 10879d02a428SJonas Bonn * pt_regs->sp so that we can easily restore it when we are made 10889d02a428SJonas Bonn * live again... 10899d02a428SJonas Bonn */ 10909d02a428SJonas Bonn 10919d02a428SJonas Bonn /* Save the old value of thread_info->ksp as pt_regs->sp */ 10929d02a428SJonas Bonn l.lwz r29,TI_KSP(r10) 10939d02a428SJonas Bonn l.sw PT_SP(r1),r29 10949d02a428SJonas Bonn 10959d02a428SJonas Bonn /* Swap kernel stack pointers */ 10969d02a428SJonas Bonn l.sw TI_KSP(r10),r1 /* Save old stack pointer */ 10979d02a428SJonas Bonn l.or r10,r4,r0 /* Set up new current_thread_info */ 10989d02a428SJonas Bonn l.lwz r1,TI_KSP(r10) /* Load new stack pointer */ 10999d02a428SJonas Bonn 11009d02a428SJonas Bonn /* Restore the old value of thread_info->ksp */ 11019d02a428SJonas Bonn l.lwz r29,PT_SP(r1) 11029d02a428SJonas Bonn l.sw TI_KSP(r10),r29 11039d02a428SJonas Bonn 11049d02a428SJonas Bonn /* ...and restore the registers, except r11 because the return value 11059d02a428SJonas Bonn * has already been set above. 11069d02a428SJonas Bonn */ 11079d02a428SJonas Bonn l.lwz r2,PT_GPR2(r1) 11089d02a428SJonas Bonn l.lwz r9,PT_GPR9(r1) 11099d02a428SJonas Bonn /* No need to restore r10 */ 11109d02a428SJonas Bonn /* ...and do not restore r11 */ 11119d02a428SJonas Bonn 1112840b66c2SStafford Horne /* Restore callee-saved registers */ 11139d02a428SJonas Bonn l.lwz r14,PT_GPR14(r1) 11149d02a428SJonas Bonn l.lwz r16,PT_GPR16(r1) 11159d02a428SJonas Bonn l.lwz r18,PT_GPR18(r1) 11169d02a428SJonas Bonn l.lwz r20,PT_GPR20(r1) 11179d02a428SJonas Bonn l.lwz r22,PT_GPR22(r1) 11189d02a428SJonas Bonn l.lwz r24,PT_GPR24(r1) 11199d02a428SJonas Bonn l.lwz r26,PT_GPR26(r1) 11209d02a428SJonas Bonn l.lwz r28,PT_GPR28(r1) 11219d02a428SJonas Bonn l.lwz r30,PT_GPR30(r1) 11229d02a428SJonas Bonn 11239d02a428SJonas Bonn /* Unwind stack to pre-switch state */ 11249d02a428SJonas Bonn l.addi r1,r1,(INT_FRAME_SIZE) 11259d02a428SJonas Bonn 1126287ad220SJonas Bonn /* Return via the link-register back to where we 'came from', where 1127287ad220SJonas Bonn * that may be either schedule(), ret_from_fork(), or 1128287ad220SJonas Bonn * ret_from_kernel_thread(). If we are returning to a new thread, 1129287ad220SJonas Bonn * we are expected to have set up the arg to schedule_tail already, 1130287ad220SJonas Bonn * hence we do so here unconditionally: 1131287ad220SJonas Bonn */ 1132ae6fef17SJonas Bonn l.lwz r3,TI_TASK(r3) /* Load 'prev' as schedule_tail arg */ 11339d02a428SJonas Bonn l.jr r9 11349d02a428SJonas Bonn l.nop 11359d02a428SJonas Bonn 11369d02a428SJonas Bonn/* ==================================================================== */ 11379d02a428SJonas Bonn 11389d02a428SJonas Bonn/* These all use the delay slot for setting the argument register, so the 11399d02a428SJonas Bonn * jump is always happening after the l.addi instruction. 11409d02a428SJonas Bonn * 11419d02a428SJonas Bonn * These are all just wrappers that don't touch the link-register r9, so the 11429d02a428SJonas Bonn * return from the "real" syscall function will return back to the syscall 11439d02a428SJonas Bonn * code that did the l.jal that brought us here. 11449d02a428SJonas Bonn */ 11459d02a428SJonas Bonn 11469d02a428SJonas Bonn/* fork requires that we save all the callee-saved registers because they 11479d02a428SJonas Bonn * are all effectively clobbered by the call to _switch. Here we store 11489d02a428SJonas Bonn * all the registers that aren't touched by the syscall fast path and thus 11499d02a428SJonas Bonn * weren't saved there. 11509d02a428SJonas Bonn */ 11519d02a428SJonas Bonn 11529d02a428SJonas Bonn_fork_save_extra_regs_and_call: 11539d02a428SJonas Bonn l.sw PT_GPR14(r1),r14 11549d02a428SJonas Bonn l.sw PT_GPR16(r1),r16 11559d02a428SJonas Bonn l.sw PT_GPR18(r1),r18 11569d02a428SJonas Bonn l.sw PT_GPR20(r1),r20 11579d02a428SJonas Bonn l.sw PT_GPR22(r1),r22 11589d02a428SJonas Bonn l.sw PT_GPR24(r1),r24 11599d02a428SJonas Bonn l.sw PT_GPR26(r1),r26 11609d02a428SJonas Bonn l.jr r29 11619d02a428SJonas Bonn l.sw PT_GPR28(r1),r28 11629d02a428SJonas Bonn 116339d91a9eSAl ViroENTRY(__sys_clone) 116439d91a9eSAl Viro l.movhi r29,hi(sys_clone) 11659d02a428SJonas Bonn l.j _fork_save_extra_regs_and_call 1166*07baf50aSStafford Horne l.ori r29,r29,lo(sys_clone) 11679d02a428SJonas Bonn 116839d91a9eSAl ViroENTRY(__sys_fork) 116939d91a9eSAl Viro l.movhi r29,hi(sys_fork) 11709d02a428SJonas Bonn l.j _fork_save_extra_regs_and_call 1171*07baf50aSStafford Horne l.ori r29,r29,lo(sys_fork) 11729d02a428SJonas Bonn 11739d02a428SJonas BonnENTRY(sys_rt_sigreturn) 1174c7990219SJonas Bonn l.jal _sys_rt_sigreturn 11759d02a428SJonas Bonn l.addi r3,r1,0 1176c7990219SJonas Bonn l.sfne r30,r0 1177c7990219SJonas Bonn l.bnf _no_syscall_trace 1178c7990219SJonas Bonn l.nop 1179c7990219SJonas Bonn l.jal do_syscall_trace_leave 1180c7990219SJonas Bonn l.addi r3,r1,0 1181c7990219SJonas Bonn_no_syscall_trace: 1182c7990219SJonas Bonn l.j _resume_userspace 1183c7990219SJonas Bonn l.nop 11849d02a428SJonas Bonn 11859d02a428SJonas Bonn/* This is a catch-all syscall for atomic instructions for the OpenRISC 1000. 11869d02a428SJonas Bonn * The functions takes a variable number of parameters depending on which 11879d02a428SJonas Bonn * particular flavour of atomic you want... parameter 1 is a flag identifying 11889d02a428SJonas Bonn * the atomic in question. Currently, this function implements the 11899d02a428SJonas Bonn * following variants: 11909d02a428SJonas Bonn * 11919d02a428SJonas Bonn * XCHG: 11929d02a428SJonas Bonn * @flag: 1 11939d02a428SJonas Bonn * @ptr1: 11949d02a428SJonas Bonn * @ptr2: 11959d02a428SJonas Bonn * Atomically exchange the values in pointers 1 and 2. 11969d02a428SJonas Bonn * 11979d02a428SJonas Bonn */ 11989d02a428SJonas Bonn 11999d02a428SJonas BonnENTRY(sys_or1k_atomic) 12009d02a428SJonas Bonn /* FIXME: This ignores r3 and always does an XCHG */ 12019d02a428SJonas Bonn DISABLE_INTERRUPTS(r17,r19) 1202207e715fSJonas Bonn l.lwz r29,0(r4) 1203207e715fSJonas Bonn l.lwz r27,0(r5) 1204207e715fSJonas Bonn l.sw 0(r4),r27 1205207e715fSJonas Bonn l.sw 0(r5),r29 12069d02a428SJonas Bonn ENABLE_INTERRUPTS(r17) 12079d02a428SJonas Bonn l.jr r9 12089d02a428SJonas Bonn l.or r11,r0,r0 12099d02a428SJonas Bonn 12109d02a428SJonas Bonn/* ============================================================[ EOF ]=== */ 1211