1ca54502bSMichal Simek/* 2ca54502bSMichal Simek * Low-level system-call handling, trap handlers and context-switching 3ca54502bSMichal Simek * 4ca54502bSMichal Simek * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu> 5ca54502bSMichal Simek * Copyright (C) 2008-2009 PetaLogix 6ca54502bSMichal Simek * Copyright (C) 2003 John Williams <jwilliams@itee.uq.edu.au> 7ca54502bSMichal Simek * Copyright (C) 2001,2002 NEC Corporation 8ca54502bSMichal Simek * Copyright (C) 2001,2002 Miles Bader <miles@gnu.org> 9ca54502bSMichal Simek * 10ca54502bSMichal Simek * This file is subject to the terms and conditions of the GNU General 11ca54502bSMichal Simek * Public License. See the file COPYING in the main directory of this 12ca54502bSMichal Simek * archive for more details. 13ca54502bSMichal Simek * 14ca54502bSMichal Simek * Written by Miles Bader <miles@gnu.org> 15ca54502bSMichal Simek * Heavily modified by John Williams for Microblaze 16ca54502bSMichal Simek */ 17ca54502bSMichal Simek 18ca54502bSMichal Simek#include <linux/sys.h> 19ca54502bSMichal Simek#include <linux/linkage.h> 20ca54502bSMichal Simek 21ca54502bSMichal Simek#include <asm/entry.h> 22ca54502bSMichal Simek#include <asm/current.h> 23ca54502bSMichal Simek#include <asm/processor.h> 24ca54502bSMichal Simek#include <asm/exceptions.h> 25ca54502bSMichal Simek#include <asm/asm-offsets.h> 26ca54502bSMichal Simek#include <asm/thread_info.h> 27ca54502bSMichal Simek 28ca54502bSMichal Simek#include <asm/page.h> 29ca54502bSMichal Simek#include <asm/unistd.h> 30ca54502bSMichal Simek 31ca54502bSMichal Simek#include <linux/errno.h> 32ca54502bSMichal Simek#include <asm/signal.h> 33ca54502bSMichal Simek 3411d51360SMichal Simek#undef DEBUG 3511d51360SMichal Simek 36d8748e73SMichal Simek#ifdef DEBUG 37d8748e73SMichal Simek/* Create space for syscalls counting. */ 38d8748e73SMichal Simek.section .data 39d8748e73SMichal Simek.global syscall_debug_table 40d8748e73SMichal Simek.align 4 41d8748e73SMichal Simeksyscall_debug_table: 42d8748e73SMichal Simek .space (__NR_syscalls * 4) 43d8748e73SMichal Simek#endif /* DEBUG */ 44d8748e73SMichal Simek 45ca54502bSMichal Simek#define C_ENTRY(name) .globl name; .align 4; name 46ca54502bSMichal Simek 47ca54502bSMichal Simek/* 48ca54502bSMichal Simek * Various ways of setting and clearing BIP in flags reg. 49ca54502bSMichal Simek * This is mucky, but necessary using microblaze version that 50ca54502bSMichal Simek * allows msr ops to write to BIP 51ca54502bSMichal Simek */ 52ca54502bSMichal Simek#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR 53ca54502bSMichal Simek .macro clear_bip 5466f7de86SMichal Simek msrclr r0, MSR_BIP 55ca54502bSMichal Simek .endm 56ca54502bSMichal Simek 57ca54502bSMichal Simek .macro set_bip 5866f7de86SMichal Simek msrset r0, MSR_BIP 59ca54502bSMichal Simek .endm 60ca54502bSMichal Simek 61ca54502bSMichal Simek .macro clear_eip 6266f7de86SMichal Simek msrclr r0, MSR_EIP 63ca54502bSMichal Simek .endm 64ca54502bSMichal Simek 65ca54502bSMichal Simek .macro set_ee 6666f7de86SMichal Simek msrset r0, MSR_EE 67ca54502bSMichal Simek .endm 68ca54502bSMichal Simek 69ca54502bSMichal Simek .macro disable_irq 7066f7de86SMichal Simek msrclr r0, MSR_IE 71ca54502bSMichal Simek .endm 72ca54502bSMichal Simek 73ca54502bSMichal Simek .macro enable_irq 7466f7de86SMichal Simek msrset r0, MSR_IE 75ca54502bSMichal Simek .endm 76ca54502bSMichal Simek 77ca54502bSMichal Simek .macro set_ums 7866f7de86SMichal Simek msrset r0, MSR_UMS 7966f7de86SMichal Simek msrclr r0, MSR_VMS 80ca54502bSMichal Simek .endm 81ca54502bSMichal Simek 82ca54502bSMichal Simek .macro set_vms 8366f7de86SMichal Simek msrclr r0, MSR_UMS 8466f7de86SMichal Simek msrset r0, MSR_VMS 85ca54502bSMichal Simek .endm 86ca54502bSMichal Simek 87b318067eSMichal Simek .macro clear_ums 8866f7de86SMichal Simek msrclr r0, MSR_UMS 89b318067eSMichal Simek .endm 90b318067eSMichal Simek 91ca54502bSMichal Simek .macro clear_vms_ums 9266f7de86SMichal Simek msrclr r0, MSR_VMS | MSR_UMS 93ca54502bSMichal Simek .endm 94ca54502bSMichal Simek#else 95ca54502bSMichal Simek .macro clear_bip 96ca54502bSMichal Simek mfs r11, rmsr 97ca54502bSMichal Simek andi r11, r11, ~MSR_BIP 98ca54502bSMichal Simek mts rmsr, r11 99ca54502bSMichal Simek .endm 100ca54502bSMichal Simek 101ca54502bSMichal Simek .macro set_bip 102ca54502bSMichal Simek mfs r11, rmsr 103ca54502bSMichal Simek ori r11, r11, MSR_BIP 104ca54502bSMichal Simek mts rmsr, r11 105ca54502bSMichal Simek .endm 106ca54502bSMichal Simek 107ca54502bSMichal Simek .macro clear_eip 108ca54502bSMichal Simek mfs r11, rmsr 109ca54502bSMichal Simek andi r11, r11, ~MSR_EIP 110ca54502bSMichal Simek mts rmsr, r11 111ca54502bSMichal Simek .endm 112ca54502bSMichal Simek 113ca54502bSMichal Simek .macro set_ee 114ca54502bSMichal Simek mfs r11, rmsr 115ca54502bSMichal Simek ori r11, r11, MSR_EE 116ca54502bSMichal Simek mts rmsr, r11 117ca54502bSMichal Simek .endm 118ca54502bSMichal Simek 119ca54502bSMichal Simek .macro disable_irq 120ca54502bSMichal Simek mfs r11, rmsr 121ca54502bSMichal Simek andi r11, r11, ~MSR_IE 122ca54502bSMichal Simek mts rmsr, r11 123ca54502bSMichal Simek .endm 124ca54502bSMichal Simek 125ca54502bSMichal Simek .macro enable_irq 126ca54502bSMichal Simek mfs r11, rmsr 127ca54502bSMichal Simek ori r11, r11, MSR_IE 128ca54502bSMichal Simek mts rmsr, r11 129ca54502bSMichal Simek .endm 130ca54502bSMichal Simek 131ca54502bSMichal Simek .macro set_ums 132ca54502bSMichal Simek mfs r11, rmsr 133ca54502bSMichal Simek ori r11, r11, MSR_VMS 134ca54502bSMichal Simek andni r11, r11, MSR_UMS 135ca54502bSMichal Simek mts rmsr, r11 136ca54502bSMichal Simek .endm 137ca54502bSMichal Simek 138ca54502bSMichal Simek .macro set_vms 139ca54502bSMichal Simek mfs r11, rmsr 140ca54502bSMichal Simek ori r11, r11, MSR_VMS 141ca54502bSMichal Simek andni r11, r11, MSR_UMS 142ca54502bSMichal Simek mts rmsr, r11 143ca54502bSMichal Simek .endm 144ca54502bSMichal Simek 145b318067eSMichal Simek .macro clear_ums 146b318067eSMichal Simek mfs r11, rmsr 147b318067eSMichal Simek andni r11, r11, MSR_UMS 148b318067eSMichal Simek mts rmsr,r11 149b318067eSMichal Simek .endm 150b318067eSMichal Simek 151ca54502bSMichal Simek .macro clear_vms_ums 152ca54502bSMichal Simek mfs r11, rmsr 153ca54502bSMichal Simek andni r11, r11, (MSR_VMS|MSR_UMS) 154ca54502bSMichal Simek mts rmsr,r11 155ca54502bSMichal Simek .endm 156ca54502bSMichal Simek#endif 157ca54502bSMichal Simek 158ca54502bSMichal Simek/* Define how to call high-level functions. With MMU, virtual mode must be 159ca54502bSMichal Simek * enabled when calling the high-level function. Clobbers R11. 160ca54502bSMichal Simek * VM_ON, VM_OFF, DO_JUMP_BIPCLR, DO_CALL 161ca54502bSMichal Simek */ 162ca54502bSMichal Simek 163ca54502bSMichal Simek/* turn on virtual protected mode save */ 164ca54502bSMichal Simek#define VM_ON \ 165ca54502bSMichal Simek set_ums; \ 166ca54502bSMichal Simek rted r0, 2f; \ 167a4a94dbfSMichal Simek nop; \ 168a4a94dbfSMichal Simek2: 169ca54502bSMichal Simek 170ca54502bSMichal Simek/* turn off virtual protected mode save and user mode save*/ 171ca54502bSMichal Simek#define VM_OFF \ 172ca54502bSMichal Simek clear_vms_ums; \ 173ca54502bSMichal Simek rted r0, TOPHYS(1f); \ 174a4a94dbfSMichal Simek nop; \ 175a4a94dbfSMichal Simek1: 176ca54502bSMichal Simek 177ca54502bSMichal Simek#define SAVE_REGS \ 1786e83557cSMichal Simek swi r2, r1, PT_R2; /* Save SDA */ \ 1796e83557cSMichal Simek swi r3, r1, PT_R3; \ 1806e83557cSMichal Simek swi r4, r1, PT_R4; \ 1816e83557cSMichal Simek swi r5, r1, PT_R5; \ 1826e83557cSMichal Simek swi r6, r1, PT_R6; \ 1836e83557cSMichal Simek swi r7, r1, PT_R7; \ 1846e83557cSMichal Simek swi r8, r1, PT_R8; \ 1856e83557cSMichal Simek swi r9, r1, PT_R9; \ 1866e83557cSMichal Simek swi r10, r1, PT_R10; \ 1876e83557cSMichal Simek swi r11, r1, PT_R11; /* save clobbered regs after rval */\ 1886e83557cSMichal Simek swi r12, r1, PT_R12; \ 1896e83557cSMichal Simek swi r13, r1, PT_R13; /* Save SDA2 */ \ 1906e83557cSMichal Simek swi r14, r1, PT_PC; /* PC, before IRQ/trap */ \ 1916e83557cSMichal Simek swi r15, r1, PT_R15; /* Save LP */ \ 1926e83557cSMichal Simek swi r16, r1, PT_R16; \ 1936e83557cSMichal Simek swi r17, r1, PT_R17; \ 1946e83557cSMichal Simek swi r18, r1, PT_R18; /* Save asm scratch reg */ \ 1956e83557cSMichal Simek swi r19, r1, PT_R19; \ 1966e83557cSMichal Simek swi r20, r1, PT_R20; \ 1976e83557cSMichal Simek swi r21, r1, PT_R21; \ 1986e83557cSMichal Simek swi r22, r1, PT_R22; \ 1996e83557cSMichal Simek swi r23, r1, PT_R23; \ 2006e83557cSMichal Simek swi r24, r1, PT_R24; \ 2016e83557cSMichal Simek swi r25, r1, PT_R25; \ 2026e83557cSMichal Simek swi r26, r1, PT_R26; \ 2036e83557cSMichal Simek swi r27, r1, PT_R27; \ 2046e83557cSMichal Simek swi r28, r1, PT_R28; \ 2056e83557cSMichal Simek swi r29, r1, PT_R29; \ 2066e83557cSMichal Simek swi r30, r1, PT_R30; \ 2076e83557cSMichal Simek swi r31, r1, PT_R31; /* Save current task reg */ \ 208ca54502bSMichal Simek mfs r11, rmsr; /* save MSR */ \ 2096e83557cSMichal Simek swi r11, r1, PT_MSR; 210ca54502bSMichal Simek 211faf154cdSMichal Simek#define RESTORE_REGS_GP \ 2126e83557cSMichal Simek lwi r2, r1, PT_R2; /* restore SDA */ \ 2136e83557cSMichal Simek lwi r3, r1, PT_R3; \ 2146e83557cSMichal Simek lwi r4, r1, PT_R4; \ 2156e83557cSMichal Simek lwi r5, r1, PT_R5; \ 2166e83557cSMichal Simek lwi r6, r1, PT_R6; \ 2176e83557cSMichal Simek lwi r7, r1, PT_R7; \ 2186e83557cSMichal Simek lwi r8, r1, PT_R8; \ 2196e83557cSMichal Simek lwi r9, r1, PT_R9; \ 2206e83557cSMichal Simek lwi r10, r1, PT_R10; \ 2216e83557cSMichal Simek lwi r11, r1, PT_R11; /* restore clobbered regs after rval */\ 2226e83557cSMichal Simek lwi r12, r1, PT_R12; \ 2236e83557cSMichal Simek lwi r13, r1, PT_R13; /* restore SDA2 */ \ 2246e83557cSMichal Simek lwi r14, r1, PT_PC; /* RESTORE_LINK PC, before IRQ/trap */\ 2256e83557cSMichal Simek lwi r15, r1, PT_R15; /* restore LP */ \ 2266e83557cSMichal Simek lwi r16, r1, PT_R16; \ 2276e83557cSMichal Simek lwi r17, r1, PT_R17; \ 2286e83557cSMichal Simek lwi r18, r1, PT_R18; /* restore asm scratch reg */ \ 2296e83557cSMichal Simek lwi r19, r1, PT_R19; \ 2306e83557cSMichal Simek lwi r20, r1, PT_R20; \ 2316e83557cSMichal Simek lwi r21, r1, PT_R21; \ 2326e83557cSMichal Simek lwi r22, r1, PT_R22; \ 2336e83557cSMichal Simek lwi r23, r1, PT_R23; \ 2346e83557cSMichal Simek lwi r24, r1, PT_R24; \ 2356e83557cSMichal Simek lwi r25, r1, PT_R25; \ 2366e83557cSMichal Simek lwi r26, r1, PT_R26; \ 2376e83557cSMichal Simek lwi r27, r1, PT_R27; \ 2386e83557cSMichal Simek lwi r28, r1, PT_R28; \ 2396e83557cSMichal Simek lwi r29, r1, PT_R29; \ 2406e83557cSMichal Simek lwi r30, r1, PT_R30; \ 2416e83557cSMichal Simek lwi r31, r1, PT_R31; /* Restore cur task reg */ 242ca54502bSMichal Simek 243faf154cdSMichal Simek#define RESTORE_REGS \ 244faf154cdSMichal Simek lwi r11, r1, PT_MSR; \ 245faf154cdSMichal Simek mts rmsr , r11; \ 246faf154cdSMichal Simek RESTORE_REGS_GP 247faf154cdSMichal Simek 24814ef905bSMichal Simek#define RESTORE_REGS_RTBD \ 24914ef905bSMichal Simek lwi r11, r1, PT_MSR; \ 25014ef905bSMichal Simek andni r11, r11, MSR_EIP; /* clear EIP */ \ 25114ef905bSMichal Simek ori r11, r11, MSR_EE | MSR_BIP; /* set EE and BIP */ \ 25214ef905bSMichal Simek mts rmsr , r11; \ 25314ef905bSMichal Simek RESTORE_REGS_GP 25414ef905bSMichal Simek 255e5d2af2bSMichal Simek#define SAVE_STATE \ 256e5d2af2bSMichal Simek swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* save stack */ \ 257e5d2af2bSMichal Simek /* See if already in kernel mode.*/ \ 258e5d2af2bSMichal Simek mfs r1, rmsr; \ 259e5d2af2bSMichal Simek andi r1, r1, MSR_UMS; \ 260e5d2af2bSMichal Simek bnei r1, 1f; \ 261e5d2af2bSMichal Simek /* Kernel-mode state save. */ \ 262e5d2af2bSMichal Simek /* Reload kernel stack-ptr. */ \ 263e5d2af2bSMichal Simek lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); \ 264287503faSMichal Simek /* FIXME: I can add these two lines to one */ \ 265287503faSMichal Simek /* tophys(r1,r1); */ \ 2666e83557cSMichal Simek /* addik r1, r1, -PT_SIZE; */ \ 2676e83557cSMichal Simek addik r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - PT_SIZE; \ 268e5d2af2bSMichal Simek SAVE_REGS \ 269e5d2af2bSMichal Simek brid 2f; \ 2706e83557cSMichal Simek swi r1, r1, PT_MODE; \ 271e5d2af2bSMichal Simek1: /* User-mode state save. */ \ 272e5d2af2bSMichal Simek lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */\ 273e5d2af2bSMichal Simek tophys(r1,r1); \ 274e5d2af2bSMichal Simek lwi r1, r1, TS_THREAD_INFO; /* get the thread info */ \ 275287503faSMichal Simek /* MS these three instructions can be added to one */ \ 276287503faSMichal Simek /* addik r1, r1, THREAD_SIZE; */ \ 277287503faSMichal Simek /* tophys(r1,r1); */ \ 2786e83557cSMichal Simek /* addik r1, r1, -PT_SIZE; */ \ 2796e83557cSMichal Simek addik r1, r1, THREAD_SIZE + CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - PT_SIZE; \ 280e5d2af2bSMichal Simek SAVE_REGS \ 281e5d2af2bSMichal Simek lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); \ 2826e83557cSMichal Simek swi r11, r1, PT_R1; /* Store user SP. */ \ 2836e83557cSMichal Simek swi r0, r1, PT_MODE; /* Was in user-mode. */ \ 284e5d2af2bSMichal Simek /* MS: I am clearing UMS even in case when I come from kernel space */ \ 285e5d2af2bSMichal Simek clear_ums; \ 286e5d2af2bSMichal Simek2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); 287e5d2af2bSMichal Simek 288ca54502bSMichal Simek.text 289ca54502bSMichal Simek 290ca54502bSMichal Simek/* 291ca54502bSMichal Simek * User trap. 292ca54502bSMichal Simek * 293ca54502bSMichal Simek * System calls are handled here. 294ca54502bSMichal Simek * 295ca54502bSMichal Simek * Syscall protocol: 296ca54502bSMichal Simek * Syscall number in r12, args in r5-r10 297ca54502bSMichal Simek * Return value in r3 298ca54502bSMichal Simek * 299ca54502bSMichal Simek * Trap entered via brki instruction, so BIP bit is set, and interrupts 300ca54502bSMichal Simek * are masked. This is nice, means we don't have to CLI before state save 301ca54502bSMichal Simek */ 302ca54502bSMichal SimekC_ENTRY(_user_exception): 3030e41c909SMichal Simek swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */ 3049da63458SMichal Simek addi r14, r14, 4 /* return address is 4 byte after call */ 305ca54502bSMichal Simek 306ca54502bSMichal Simek lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */ 307ca54502bSMichal Simek tophys(r1,r1); 308ca54502bSMichal Simek lwi r1, r1, TS_THREAD_INFO; /* get stack from task_struct */ 3099da63458SMichal Simek/* calculate kernel stack pointer from task struct 8k */ 3109da63458SMichal Simek addik r1, r1, THREAD_SIZE; 3119da63458SMichal Simek tophys(r1,r1); 3129da63458SMichal Simek 3136e83557cSMichal Simek addik r1, r1, -PT_SIZE; /* Make room on the stack. */ 314ca54502bSMichal Simek SAVE_REGS 3156e83557cSMichal Simek swi r0, r1, PT_R3 3166e83557cSMichal Simek swi r0, r1, PT_R4 317ca54502bSMichal Simek 3186e83557cSMichal Simek swi r0, r1, PT_MODE; /* Was in user-mode. */ 319ca54502bSMichal Simek lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); 3206e83557cSMichal Simek swi r11, r1, PT_R1; /* Store user SP. */ 32125f6e596SMichal Simek clear_ums; 3229da63458SMichal Simek2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); 323ca54502bSMichal Simek /* Save away the syscall number. */ 3246e83557cSMichal Simek swi r12, r1, PT_R0; 325ca54502bSMichal Simek tovirt(r1,r1) 326ca54502bSMichal Simek 327ca54502bSMichal Simek/* where the trap should return need -8 to adjust for rtsd r15, 8*/ 328ca54502bSMichal Simek/* Jump to the appropriate function for the system call number in r12 329ca54502bSMichal Simek * (r12 is not preserved), or return an error if r12 is not valid. The LP 330ca54502bSMichal Simek * register should point to the location where 331ca54502bSMichal Simek * the called function should return. [note that MAKE_SYS_CALL uses label 1] */ 33223575483SMichal Simek 33325f6e596SMichal Simek /* Step into virtual mode */ 33425f6e596SMichal Simek rtbd r0, 3f 33523575483SMichal Simek nop 33623575483SMichal Simek3: 337b1d70c62SMichal Simek lwi r11, CURRENT_TASK, TS_THREAD_INFO /* get thread info */ 33823575483SMichal Simek lwi r11, r11, TI_FLAGS /* get flags in thread info */ 33923575483SMichal Simek andi r11, r11, _TIF_WORK_SYSCALL_MASK 34023575483SMichal Simek beqi r11, 4f 34123575483SMichal Simek 34223575483SMichal Simek addik r3, r0, -ENOSYS 3436e83557cSMichal Simek swi r3, r1, PT_R3 34423575483SMichal Simek brlid r15, do_syscall_trace_enter 3456e83557cSMichal Simek addik r5, r1, PT_R0 34623575483SMichal Simek 34723575483SMichal Simek # do_syscall_trace_enter returns the new syscall nr. 34823575483SMichal Simek addk r12, r0, r3 3496e83557cSMichal Simek lwi r5, r1, PT_R5; 3506e83557cSMichal Simek lwi r6, r1, PT_R6; 3516e83557cSMichal Simek lwi r7, r1, PT_R7; 3526e83557cSMichal Simek lwi r8, r1, PT_R8; 3536e83557cSMichal Simek lwi r9, r1, PT_R9; 3546e83557cSMichal Simek lwi r10, r1, PT_R10; 35523575483SMichal Simek4: 35623575483SMichal Simek/* Jump to the appropriate function for the system call number in r12 35723575483SMichal Simek * (r12 is not preserved), or return an error if r12 is not valid. 35823575483SMichal Simek * The LP register should point to the location where the called function 35923575483SMichal Simek * should return. [note that MAKE_SYS_CALL uses label 1] */ 36023575483SMichal Simek /* See if the system call number is valid */ 361c2219edaSJamie Garside blti r12, 5f 362ca54502bSMichal Simek addi r11, r12, -__NR_syscalls; 36323575483SMichal Simek bgei r11, 5f; 364ca54502bSMichal Simek /* Figure out which function to use for this system call. */ 365ca54502bSMichal Simek /* Note Microblaze barrel shift is optional, so don't rely on it */ 366ca54502bSMichal Simek add r12, r12, r12; /* convert num -> ptr */ 367ca54502bSMichal Simek add r12, r12, r12; 3684de6ba68SMichal Simek addi r30, r0, 1 /* restarts allowed */ 369ca54502bSMichal Simek 37011d51360SMichal Simek#ifdef DEBUG 371d8748e73SMichal Simek /* Trac syscalls and stored them to syscall_debug_table */ 372d8748e73SMichal Simek /* The first syscall location stores total syscall number */ 373d8748e73SMichal Simek lwi r3, r0, syscall_debug_table 374ca54502bSMichal Simek addi r3, r3, 1 375d8748e73SMichal Simek swi r3, r0, syscall_debug_table 376d8748e73SMichal Simek lwi r3, r12, syscall_debug_table 377d8748e73SMichal Simek addi r3, r3, 1 378d8748e73SMichal Simek swi r3, r12, syscall_debug_table 37911d51360SMichal Simek#endif 380ca54502bSMichal Simek 38123575483SMichal Simek # Find and jump into the syscall handler. 38223575483SMichal Simek lwi r12, r12, sys_call_table 38323575483SMichal Simek /* where the trap should return need -8 to adjust for rtsd r15, 8 */ 384b9ea77e2SMichal Simek addi r15, r0, ret_from_trap-8 38523575483SMichal Simek bra r12 38623575483SMichal Simek 387ca54502bSMichal Simek /* The syscall number is invalid, return an error. */ 38823575483SMichal Simek5: 389c2219edaSJamie Garside braid ret_from_trap 3909814cc11SMichal Simek addi r3, r0, -ENOSYS; 391ca54502bSMichal Simek 39223575483SMichal Simek/* Entry point used to return from a syscall/trap */ 393ca54502bSMichal Simek/* We re-enable BIP bit before state restore */ 394ca54502bSMichal SimekC_ENTRY(ret_from_trap): 3956e83557cSMichal Simek swi r3, r1, PT_R3 3966e83557cSMichal Simek swi r4, r1, PT_R4 397b1d70c62SMichal Simek 3986e83557cSMichal Simek lwi r11, r1, PT_MODE; 3999da63458SMichal Simek/* See if returning to kernel mode, if so, skip resched &c. */ 4009da63458SMichal Simek bnei r11, 2f; 401ca54502bSMichal Simek /* We're returning to user mode, so check for various conditions that 402ca54502bSMichal Simek * trigger rescheduling. */ 403b1d70c62SMichal Simek /* FIXME: Restructure all these flag checks. */ 404b1d70c62SMichal Simek lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */ 40523575483SMichal Simek lwi r11, r11, TI_FLAGS; /* get flags in thread info */ 40623575483SMichal Simek andi r11, r11, _TIF_WORK_SYSCALL_MASK 40723575483SMichal Simek beqi r11, 1f 40823575483SMichal Simek 40923575483SMichal Simek brlid r15, do_syscall_trace_leave 4106e83557cSMichal Simek addik r5, r1, PT_R0 41123575483SMichal Simek1: 41223575483SMichal Simek /* We're returning to user mode, so check for various conditions that 41323575483SMichal Simek * trigger rescheduling. */ 414b1d70c62SMichal Simek /* get thread info from current task */ 415b1d70c62SMichal Simek lwi r11, CURRENT_TASK, TS_THREAD_INFO; 416e9f92526SAl Viro lwi r19, r11, TI_FLAGS; /* get flags in thread info */ 417e9f92526SAl Viro andi r11, r19, _TIF_NEED_RESCHED; 418ca54502bSMichal Simek beqi r11, 5f; 419ca54502bSMichal Simek 420ca54502bSMichal Simek bralid r15, schedule; /* Call scheduler */ 421ca54502bSMichal Simek nop; /* delay slot */ 422e9f92526SAl Viro bri 1b 423ca54502bSMichal Simek 424ca54502bSMichal Simek /* Maybe handle a signal */ 425e9f92526SAl Viro5: 426e9f92526SAl Viro andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME; 427e9f92526SAl Viro beqi r11, 4f; /* Signals to handle, handle them */ 428ca54502bSMichal Simek 4296e83557cSMichal Simek addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */ 430969a9616SAl Viro bralid r15, do_notify_resume; /* Handle any signals */ 43114203e19SAl Viro add r6, r30, r0; /* Arg 2: int in_syscall */ 432e9f92526SAl Viro add r30, r0, r0 /* no more restarts */ 433e9f92526SAl Viro bri 1b 434b1d70c62SMichal Simek 435b1d70c62SMichal Simek/* Finally, return to user state. */ 436e9f92526SAl Viro4: set_bip; /* Ints masked for state restore */ 4378633bebcSMichal Simek swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */ 438ca54502bSMichal Simek VM_OFF; 439ca54502bSMichal Simek tophys(r1,r1); 44014ef905bSMichal Simek RESTORE_REGS_RTBD; 4416e83557cSMichal Simek addik r1, r1, PT_SIZE /* Clean up stack space. */ 442ca54502bSMichal Simek lwi r1, r1, PT_R1 - PT_SIZE;/* Restore user stack pointer. */ 4439da63458SMichal Simek bri 6f; 4449da63458SMichal Simek 4459da63458SMichal Simek/* Return to kernel state. */ 4469da63458SMichal Simek2: set_bip; /* Ints masked for state restore */ 4479da63458SMichal Simek VM_OFF; 4489da63458SMichal Simek tophys(r1,r1); 44914ef905bSMichal Simek RESTORE_REGS_RTBD; 4506e83557cSMichal Simek addik r1, r1, PT_SIZE /* Clean up stack space. */ 4519da63458SMichal Simek tovirt(r1,r1); 4529da63458SMichal Simek6: 453ca54502bSMichal SimekTRAP_return: /* Make global symbol for debugging */ 454ca54502bSMichal Simek rtbd r14, 0; /* Instructions to return from an IRQ */ 455ca54502bSMichal Simek nop; 456ca54502bSMichal Simek 457ca54502bSMichal Simek 458ca54502bSMichal Simek/* This the initial entry point for a new child thread, with an appropriate 4595b7d1d57SSlark Xiao stack in place that makes it look like the child is in the middle of a 460ca54502bSMichal Simek syscall. This function is actually `returned to' from switch_thread 461ca54502bSMichal Simek (copy_thread makes ret_from_fork the return address in each new thread's 462ca54502bSMichal Simek saved context). */ 463ca54502bSMichal SimekC_ENTRY(ret_from_fork): 464ca54502bSMichal Simek bralid r15, schedule_tail; /* ...which is schedule_tail's arg */ 465fd11ff73SMichal Simek add r5, r3, r0; /* switch_thread returns the prev task */ 466ca54502bSMichal Simek /* ( in the delay slot ) */ 467ca54502bSMichal Simek brid ret_from_trap; /* Do normal trap return */ 4689814cc11SMichal Simek add r3, r0, r0; /* Child's fork call should return 0. */ 469ca54502bSMichal Simek 4702319295dSAl ViroC_ENTRY(ret_from_kernel_thread): 4712319295dSAl Viro bralid r15, schedule_tail; /* ...which is schedule_tail's arg */ 4722319295dSAl Viro add r5, r3, r0; /* switch_thread returns the prev task */ 4732319295dSAl Viro /* ( in the delay slot ) */ 4742319295dSAl Viro brald r15, r20 /* fn was left in r20 */ 4752319295dSAl Viro addk r5, r0, r19 /* ... and argument - in r19 */ 47699c59f60SAl Viro brid ret_from_trap 47799c59f60SAl Viro add r3, r0, r0 4782319295dSAl Viro 479ca54502bSMichal SimekC_ENTRY(sys_rt_sigreturn_wrapper): 48014203e19SAl Viro addik r30, r0, 0 /* no restarts */ 481791d0a16SMichal Simek brid sys_rt_sigreturn /* Do real work */ 4826e83557cSMichal Simek addik r5, r1, 0; /* add user context as 1st arg */ 483ca54502bSMichal Simek 484ca54502bSMichal Simek/* 485ca54502bSMichal Simek * HW EXCEPTION rutine start 486ca54502bSMichal Simek */ 487ca54502bSMichal SimekC_ENTRY(full_exception_trap): 488ca54502bSMichal Simek /* adjust exception address for privileged instruction 489ca54502bSMichal Simek * for finding where is it */ 490ca54502bSMichal Simek addik r17, r17, -4 491ca54502bSMichal Simek SAVE_STATE /* Save registers */ 49206a54604SMichal Simek /* PC, before IRQ/trap - this is one instruction above */ 4936e83557cSMichal Simek swi r17, r1, PT_PC; 49406a54604SMichal Simek tovirt(r1,r1) 495ca54502bSMichal Simek /* FIXME this can be store directly in PT_ESR reg. 496ca54502bSMichal Simek * I tested it but there is a fault */ 497ca54502bSMichal Simek /* where the trap should return need -8 to adjust for rtsd r15, 8 */ 498b9ea77e2SMichal Simek addik r15, r0, ret_from_exc - 8 499ca54502bSMichal Simek mfs r6, resr 500ca54502bSMichal Simek mfs r7, rfsr; /* save FSR */ 501131e4e97SMichal Simek mts rfsr, r0; /* Clear sticky fsr */ 502c318d483SMichal Simek rted r0, full_exception 5036e83557cSMichal Simek addik r5, r1, 0 /* parameter struct pt_regs * regs */ 504ca54502bSMichal Simek 505ca54502bSMichal Simek/* 506ca54502bSMichal Simek * Unaligned data trap. 507ca54502bSMichal Simek * 508ca54502bSMichal Simek * Unaligned data trap last on 4k page is handled here. 509ca54502bSMichal Simek * 510ca54502bSMichal Simek * Trap entered via exception, so EE bit is set, and interrupts 511ca54502bSMichal Simek * are masked. This is nice, means we don't have to CLI before state save 512ca54502bSMichal Simek * 513ca54502bSMichal Simek * The assembler routine is in "arch/microblaze/kernel/hw_exception_handler.S" 514ca54502bSMichal Simek */ 515ca54502bSMichal SimekC_ENTRY(unaligned_data_trap): 5168b110d15SMichal Simek /* MS: I have to save r11 value and then restore it because 5178b110d15SMichal Simek * set_bit, clear_eip, set_ee use r11 as temp register if MSR 5188b110d15SMichal Simek * instructions are not used. We don't need to do if MSR instructions 5198b110d15SMichal Simek * are used and they use r0 instead of r11. 5208b110d15SMichal Simek * I am using ENTRY_SP which should be primary used only for stack 5218b110d15SMichal Simek * pointer saving. */ 5228b110d15SMichal Simek swi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); 5238b110d15SMichal Simek set_bip; /* equalize initial state for all possible entries */ 5248b110d15SMichal Simek clear_eip; 5258b110d15SMichal Simek set_ee; 5268b110d15SMichal Simek lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); 527ca54502bSMichal Simek SAVE_STATE /* Save registers.*/ 52806a54604SMichal Simek /* PC, before IRQ/trap - this is one instruction above */ 5296e83557cSMichal Simek swi r17, r1, PT_PC; 53006a54604SMichal Simek tovirt(r1,r1) 531ca54502bSMichal Simek /* where the trap should return need -8 to adjust for rtsd r15, 8 */ 532b9ea77e2SMichal Simek addik r15, r0, ret_from_exc-8 533ca54502bSMichal Simek mfs r3, resr /* ESR */ 534ca54502bSMichal Simek mfs r4, rear /* EAR */ 535c318d483SMichal Simek rtbd r0, _unaligned_data_exception 5366e83557cSMichal Simek addik r7, r1, 0 /* parameter struct pt_regs * regs */ 537ca54502bSMichal Simek 538ca54502bSMichal Simek/* 539ca54502bSMichal Simek * Page fault traps. 540ca54502bSMichal Simek * 541ca54502bSMichal Simek * If the real exception handler (from hw_exception_handler.S) didn't find 542ca54502bSMichal Simek * the mapping for the process, then we're thrown here to handle such situation. 543ca54502bSMichal Simek * 544ca54502bSMichal Simek * Trap entered via exceptions, so EE bit is set, and interrupts 545ca54502bSMichal Simek * are masked. This is nice, means we don't have to CLI before state save 546ca54502bSMichal Simek * 547ca54502bSMichal Simek * Build a standard exception frame for TLB Access errors. All TLB exceptions 548ca54502bSMichal Simek * will bail out to this point if they can't resolve the lightweight TLB fault. 549ca54502bSMichal Simek * 550ca54502bSMichal Simek * The C function called is in "arch/microblaze/mm/fault.c", declared as: 551ca54502bSMichal Simek * void do_page_fault(struct pt_regs *regs, 552ca54502bSMichal Simek * unsigned long address, 553ca54502bSMichal Simek * unsigned long error_code) 554ca54502bSMichal Simek */ 555ca54502bSMichal Simek/* data and intruction trap - which is choose is resolved int fault.c */ 556ca54502bSMichal SimekC_ENTRY(page_fault_data_trap): 557ca54502bSMichal Simek SAVE_STATE /* Save registers.*/ 55806a54604SMichal Simek /* PC, before IRQ/trap - this is one instruction above */ 5596e83557cSMichal Simek swi r17, r1, PT_PC; 56006a54604SMichal Simek tovirt(r1,r1) 561ca54502bSMichal Simek /* where the trap should return need -8 to adjust for rtsd r15, 8 */ 562b9ea77e2SMichal Simek addik r15, r0, ret_from_exc-8 563ca54502bSMichal Simek mfs r6, rear /* parameter unsigned long address */ 564ca54502bSMichal Simek mfs r7, resr /* parameter unsigned long error_code */ 565c318d483SMichal Simek rted r0, do_page_fault 5666e83557cSMichal Simek addik r5, r1, 0 /* parameter struct pt_regs * regs */ 567ca54502bSMichal Simek 568ca54502bSMichal SimekC_ENTRY(page_fault_instr_trap): 569ca54502bSMichal Simek SAVE_STATE /* Save registers.*/ 57006a54604SMichal Simek /* PC, before IRQ/trap - this is one instruction above */ 5716e83557cSMichal Simek swi r17, r1, PT_PC; 57206a54604SMichal Simek tovirt(r1,r1) 573ca54502bSMichal Simek /* where the trap should return need -8 to adjust for rtsd r15, 8 */ 574b9ea77e2SMichal Simek addik r15, r0, ret_from_exc-8 575ca54502bSMichal Simek mfs r6, rear /* parameter unsigned long address */ 576ca54502bSMichal Simek ori r7, r0, 0 /* parameter unsigned long error_code */ 5779814cc11SMichal Simek rted r0, do_page_fault 5786e83557cSMichal Simek addik r5, r1, 0 /* parameter struct pt_regs * regs */ 579ca54502bSMichal Simek 580ca54502bSMichal Simek/* Entry point used to return from an exception. */ 581ca54502bSMichal SimekC_ENTRY(ret_from_exc): 5826e83557cSMichal Simek lwi r11, r1, PT_MODE; 583ca54502bSMichal Simek bnei r11, 2f; /* See if returning to kernel mode, */ 584ca54502bSMichal Simek /* ... if so, skip resched &c. */ 585ca54502bSMichal Simek 586ca54502bSMichal Simek /* We're returning to user mode, so check for various conditions that 587ca54502bSMichal Simek trigger rescheduling. */ 588e9f92526SAl Viro1: 589b1d70c62SMichal Simek lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */ 590e9f92526SAl Viro lwi r19, r11, TI_FLAGS; /* get flags in thread info */ 591e9f92526SAl Viro andi r11, r19, _TIF_NEED_RESCHED; 592ca54502bSMichal Simek beqi r11, 5f; 593ca54502bSMichal Simek 594ca54502bSMichal Simek/* Call the scheduler before returning from a syscall/trap. */ 595ca54502bSMichal Simek bralid r15, schedule; /* Call scheduler */ 596ca54502bSMichal Simek nop; /* delay slot */ 597e9f92526SAl Viro bri 1b 598ca54502bSMichal Simek 599ca54502bSMichal Simek /* Maybe handle a signal */ 600e9f92526SAl Viro5: andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME; 601e9f92526SAl Viro beqi r11, 4f; /* Signals to handle, handle them */ 602ca54502bSMichal Simek 603ca54502bSMichal Simek /* 604ca54502bSMichal Simek * Handle a signal return; Pending signals should be in r18. 605ca54502bSMichal Simek * 606ca54502bSMichal Simek * Not all registers are saved by the normal trap/interrupt entry 607ca54502bSMichal Simek * points (for instance, call-saved registers (because the normal 608ca54502bSMichal Simek * C-compiler calling sequence in the kernel makes sure they're 609ca54502bSMichal Simek * preserved), and call-clobbered registers in the case of 610ca54502bSMichal Simek * traps), but signal handlers may want to examine or change the 611ca54502bSMichal Simek * complete register state. Here we save anything not saved by 612ca54502bSMichal Simek * the normal entry sequence, so that it may be safely restored 613969a9616SAl Viro * (in a possibly modified form) after do_notify_resume returns. */ 6146e83557cSMichal Simek addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */ 615969a9616SAl Viro bralid r15, do_notify_resume; /* Handle any signals */ 61683140191SAl Viro addi r6, r0, 0; /* Arg 2: int in_syscall */ 617e9f92526SAl Viro bri 1b 618ca54502bSMichal Simek 619ca54502bSMichal Simek/* Finally, return to user state. */ 620e9f92526SAl Viro4: set_bip; /* Ints masked for state restore */ 6218633bebcSMichal Simek swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */ 622ca54502bSMichal Simek VM_OFF; 623ca54502bSMichal Simek tophys(r1,r1); 624ca54502bSMichal Simek 62514ef905bSMichal Simek RESTORE_REGS_RTBD; 6266e83557cSMichal Simek addik r1, r1, PT_SIZE /* Clean up stack space. */ 627ca54502bSMichal Simek 628ca54502bSMichal Simek lwi r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer. */ 629ca54502bSMichal Simek bri 6f; 630ca54502bSMichal Simek/* Return to kernel state. */ 63196014cc3SMichal Simek2: set_bip; /* Ints masked for state restore */ 63296014cc3SMichal Simek VM_OFF; 633ca54502bSMichal Simek tophys(r1,r1); 63414ef905bSMichal Simek RESTORE_REGS_RTBD; 6356e83557cSMichal Simek addik r1, r1, PT_SIZE /* Clean up stack space. */ 636ca54502bSMichal Simek 637ca54502bSMichal Simek tovirt(r1,r1); 638ca54502bSMichal Simek6: 639ca54502bSMichal SimekEXC_return: /* Make global symbol for debugging */ 640ca54502bSMichal Simek rtbd r14, 0; /* Instructions to return from an IRQ */ 641ca54502bSMichal Simek nop; 642ca54502bSMichal Simek 643ca54502bSMichal Simek/* 644ca54502bSMichal Simek * HW EXCEPTION rutine end 645ca54502bSMichal Simek */ 646ca54502bSMichal Simek 647ca54502bSMichal Simek/* 648ca54502bSMichal Simek * Hardware maskable interrupts. 649ca54502bSMichal Simek * 650ca54502bSMichal Simek * The stack-pointer (r1) should have already been saved to the memory 651ca54502bSMichal Simek * location PER_CPU(ENTRY_SP). 652ca54502bSMichal Simek */ 653ca54502bSMichal SimekC_ENTRY(_interrupt): 654ca54502bSMichal Simek/* MS: we are in physical address */ 655ca54502bSMichal Simek/* Save registers, switch to proper stack, convert SP to virtual.*/ 656ca54502bSMichal Simek swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) 657ca54502bSMichal Simek /* MS: See if already in kernel mode. */ 658653e447eSMichal Simek mfs r1, rmsr 6595c0d72b1SMichal Simek nop 660653e447eSMichal Simek andi r1, r1, MSR_UMS 661653e447eSMichal Simek bnei r1, 1f 662ca54502bSMichal Simek 663ca54502bSMichal Simek/* Kernel-mode state save. */ 664653e447eSMichal Simek lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) 665653e447eSMichal Simek tophys(r1,r1); /* MS: I have in r1 physical address where stack is */ 666ca54502bSMichal Simek /* save registers */ 667ca54502bSMichal Simek/* MS: Make room on the stack -> activation record */ 6686e83557cSMichal Simek addik r1, r1, -PT_SIZE; 669ca54502bSMichal Simek SAVE_REGS 670ca54502bSMichal Simek brid 2f; 6716e83557cSMichal Simek swi r1, r1, PT_MODE; /* 0 - user mode, 1 - kernel mode */ 672ca54502bSMichal Simek1: 673ca54502bSMichal Simek/* User-mode state save. */ 674ca54502bSMichal Simek /* MS: get the saved current */ 675ca54502bSMichal Simek lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); 676ca54502bSMichal Simek tophys(r1,r1); 677ca54502bSMichal Simek lwi r1, r1, TS_THREAD_INFO; 678ca54502bSMichal Simek addik r1, r1, THREAD_SIZE; 679ca54502bSMichal Simek tophys(r1,r1); 680ca54502bSMichal Simek /* save registers */ 6816e83557cSMichal Simek addik r1, r1, -PT_SIZE; 682ca54502bSMichal Simek SAVE_REGS 683ca54502bSMichal Simek /* calculate mode */ 6846e83557cSMichal Simek swi r0, r1, PT_MODE; 685ca54502bSMichal Simek lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); 6866e83557cSMichal Simek swi r11, r1, PT_R1; 68780c5ff6bSMichal Simek clear_ums; 688ca54502bSMichal Simek2: 689b1d70c62SMichal Simek lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); 690ca54502bSMichal Simek tovirt(r1,r1) 691b9ea77e2SMichal Simek addik r15, r0, irq_call; 69280c5ff6bSMichal Simekirq_call:rtbd r0, do_IRQ; 6936e83557cSMichal Simek addik r5, r1, 0; 694ca54502bSMichal Simek 695ca54502bSMichal Simek/* MS: we are in virtual mode */ 696ca54502bSMichal Simekret_from_irq: 6976e83557cSMichal Simek lwi r11, r1, PT_MODE; 698ca54502bSMichal Simek bnei r11, 2f; 699ca54502bSMichal Simek 700e9f92526SAl Viro1: 701b1d70c62SMichal Simek lwi r11, CURRENT_TASK, TS_THREAD_INFO; 702e9f92526SAl Viro lwi r19, r11, TI_FLAGS; /* MS: get flags from thread info */ 703e9f92526SAl Viro andi r11, r19, _TIF_NEED_RESCHED; 704ca54502bSMichal Simek beqi r11, 5f 705ca54502bSMichal Simek bralid r15, schedule; 706ca54502bSMichal Simek nop; /* delay slot */ 707e9f92526SAl Viro bri 1b 708ca54502bSMichal Simek 709ca54502bSMichal Simek /* Maybe handle a signal */ 710e9f92526SAl Viro5: andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME; 711ca54502bSMichal Simek beqid r11, no_intr_resched 712ca54502bSMichal Simek/* Handle a signal return; Pending signals should be in r18. */ 7136e83557cSMichal Simek addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */ 714969a9616SAl Viro bralid r15, do_notify_resume; /* Handle any signals */ 71583140191SAl Viro addi r6, r0, 0; /* Arg 2: int in_syscall */ 716e9f92526SAl Viro bri 1b 717ca54502bSMichal Simek 718ca54502bSMichal Simek/* Finally, return to user state. */ 719ca54502bSMichal Simekno_intr_resched: 720ca54502bSMichal Simek /* Disable interrupts, we are now committed to the state restore */ 721ca54502bSMichal Simek disable_irq 7228633bebcSMichal Simek swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); 723ca54502bSMichal Simek VM_OFF; 724ca54502bSMichal Simek tophys(r1,r1); 725ca54502bSMichal Simek RESTORE_REGS 7266e83557cSMichal Simek addik r1, r1, PT_SIZE /* MS: Clean up stack space. */ 727ca54502bSMichal Simek lwi r1, r1, PT_R1 - PT_SIZE; 728ca54502bSMichal Simek bri 6f; 729ca54502bSMichal Simek/* MS: Return to kernel state. */ 73077753790SMichal Simek2: 73118803733SThomas Gleixner#ifdef CONFIG_PREEMPTION 732b1d70c62SMichal Simek lwi r11, CURRENT_TASK, TS_THREAD_INFO; 73377753790SMichal Simek /* MS: get preempt_count from thread info */ 73477753790SMichal Simek lwi r5, r11, TI_PREEMPT_COUNT; 73577753790SMichal Simek bgti r5, restore; 73677753790SMichal Simek 73777753790SMichal Simek lwi r5, r11, TI_FLAGS; /* get flags in thread info */ 73877753790SMichal Simek andi r5, r5, _TIF_NEED_RESCHED; 73977753790SMichal Simek beqi r5, restore /* if zero jump over */ 74077753790SMichal Simek 74177753790SMichal Simek /* interrupts are off that's why I am calling preempt_chedule_irq */ 74277753790SMichal Simek bralid r15, preempt_schedule_irq 74377753790SMichal Simek nop 74477753790SMichal Simekrestore: 74577753790SMichal Simek#endif 74677753790SMichal Simek VM_OFF /* MS: turn off MMU */ 747ca54502bSMichal Simek tophys(r1,r1) 748ca54502bSMichal Simek RESTORE_REGS 7496e83557cSMichal Simek addik r1, r1, PT_SIZE /* MS: Clean up stack space. */ 750ca54502bSMichal Simek tovirt(r1,r1); 751ca54502bSMichal Simek6: 752ca54502bSMichal SimekIRQ_return: /* MS: Make global symbol for debugging */ 753ca54502bSMichal Simek rtid r14, 0 754ca54502bSMichal Simek nop 755ca54502bSMichal Simek 756ca54502bSMichal Simek/* 7572d5973cbSMichal Simek * Debug trap for KGDB. Enter to _debug_exception by brki r16, 0x18 7582d5973cbSMichal Simek * and call handling function with saved pt_regs 759ca54502bSMichal Simek */ 760ca54502bSMichal SimekC_ENTRY(_debug_exception): 761ca54502bSMichal Simek /* BIP bit is set on entry, no interrupts can occur */ 762ca54502bSMichal Simek swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) 763ca54502bSMichal Simek 764653e447eSMichal Simek mfs r1, rmsr 7655c0d72b1SMichal Simek nop 766653e447eSMichal Simek andi r1, r1, MSR_UMS 767653e447eSMichal Simek bnei r1, 1f 7682d5973cbSMichal Simek/* MS: Kernel-mode state save - kgdb */ 769653e447eSMichal Simek lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/ 770ca54502bSMichal Simek 7712d5973cbSMichal Simek /* BIP bit is set on entry, no interrupts can occur */ 7726e83557cSMichal Simek addik r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - PT_SIZE; 773ca54502bSMichal Simek SAVE_REGS; 7742d5973cbSMichal Simek /* save all regs to pt_reg structure */ 7756e83557cSMichal Simek swi r0, r1, PT_R0; /* R0 must be saved too */ 7766e83557cSMichal Simek swi r14, r1, PT_R14 /* rewrite saved R14 value */ 7776e83557cSMichal Simek swi r16, r1, PT_PC; /* PC and r16 are the same */ 7782d5973cbSMichal Simek /* save special purpose registers to pt_regs */ 7792d5973cbSMichal Simek mfs r11, rear; 7806e83557cSMichal Simek swi r11, r1, PT_EAR; 7812d5973cbSMichal Simek mfs r11, resr; 7826e83557cSMichal Simek swi r11, r1, PT_ESR; 7832d5973cbSMichal Simek mfs r11, rfsr; 7846e83557cSMichal Simek swi r11, r1, PT_FSR; 785ca54502bSMichal Simek 7862d5973cbSMichal Simek /* stack pointer is in physical address at it is decrease 7876e83557cSMichal Simek * by PT_SIZE but we need to get correct R1 value */ 7886e83557cSMichal Simek addik r11, r1, CONFIG_KERNEL_START - CONFIG_KERNEL_BASE_ADDR + PT_SIZE; 7896e83557cSMichal Simek swi r11, r1, PT_R1 7902d5973cbSMichal Simek /* MS: r31 - current pointer isn't changed */ 7912d5973cbSMichal Simek tovirt(r1,r1) 7922d5973cbSMichal Simek#ifdef CONFIG_KGDB 7936e83557cSMichal Simek addi r5, r1, 0 /* pass pt_reg address as the first arg */ 794cd341577SMichal Simek addik r15, r0, dbtrap_call; /* return address */ 7952d5973cbSMichal Simek rtbd r0, microblaze_kgdb_break 7962d5973cbSMichal Simek nop; 7972d5973cbSMichal Simek#endif 7982d5973cbSMichal Simek /* MS: Place handler for brki from kernel space if KGDB is OFF. 7992d5973cbSMichal Simek * It is very unlikely that another brki instruction is called. */ 8002d5973cbSMichal Simek bri 0 8012d5973cbSMichal Simek 8022d5973cbSMichal Simek/* MS: User-mode state save - gdb */ 8032d5973cbSMichal Simek1: lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */ 804ca54502bSMichal Simek tophys(r1,r1); 805ca54502bSMichal Simek lwi r1, r1, TS_THREAD_INFO; /* get the thread info */ 806ca54502bSMichal Simek addik r1, r1, THREAD_SIZE; /* calculate kernel stack pointer */ 807ca54502bSMichal Simek tophys(r1,r1); 808ca54502bSMichal Simek 8096e83557cSMichal Simek addik r1, r1, -PT_SIZE; /* Make room on the stack. */ 810ca54502bSMichal Simek SAVE_REGS; 8116e83557cSMichal Simek swi r16, r1, PT_PC; /* Save LP */ 8126e83557cSMichal Simek swi r0, r1, PT_MODE; /* Was in user-mode. */ 813ca54502bSMichal Simek lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); 8146e83557cSMichal Simek swi r11, r1, PT_R1; /* Store user SP. */ 8152d5973cbSMichal Simek lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); 816ca54502bSMichal Simek tovirt(r1,r1) 81706b28640SMichal Simek set_vms; 8186e83557cSMichal Simek addik r5, r1, 0; 819b9ea77e2SMichal Simek addik r15, r0, dbtrap_call; 8202d5973cbSMichal Simekdbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */ 821751f1605SMichal Simek rtbd r0, sw_exception 822751f1605SMichal Simek nop 823ca54502bSMichal Simek 8242d5973cbSMichal Simek /* MS: The first instruction for the second part of the gdb/kgdb */ 825ca54502bSMichal Simek set_bip; /* Ints masked for state restore */ 8266e83557cSMichal Simek lwi r11, r1, PT_MODE; 827ca54502bSMichal Simek bnei r11, 2f; 8282d5973cbSMichal Simek/* MS: Return to user space - gdb */ 829e9f92526SAl Viro1: 830ca54502bSMichal Simek /* Get current task ptr into r11 */ 831b1d70c62SMichal Simek lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */ 832e9f92526SAl Viro lwi r19, r11, TI_FLAGS; /* get flags in thread info */ 833e9f92526SAl Viro andi r11, r19, _TIF_NEED_RESCHED; 834ca54502bSMichal Simek beqi r11, 5f; 835ca54502bSMichal Simek 836ca54502bSMichal Simek /* Call the scheduler before returning from a syscall/trap. */ 837ca54502bSMichal Simek bralid r15, schedule; /* Call scheduler */ 838ca54502bSMichal Simek nop; /* delay slot */ 839e9f92526SAl Viro bri 1b 840ca54502bSMichal Simek 841ca54502bSMichal Simek /* Maybe handle a signal */ 842e9f92526SAl Viro5: andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME; 843e9f92526SAl Viro beqi r11, 4f; /* Signals to handle, handle them */ 844ca54502bSMichal Simek 8456e83557cSMichal Simek addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */ 846969a9616SAl Viro bralid r15, do_notify_resume; /* Handle any signals */ 84783140191SAl Viro addi r6, r0, 0; /* Arg 2: int in_syscall */ 848e9f92526SAl Viro bri 1b 849ca54502bSMichal Simek 850ca54502bSMichal Simek/* Finally, return to user state. */ 851e9f92526SAl Viro4: swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */ 852ca54502bSMichal Simek VM_OFF; 853ca54502bSMichal Simek tophys(r1,r1); 8542d5973cbSMichal Simek /* MS: Restore all regs */ 85514ef905bSMichal Simek RESTORE_REGS_RTBD 8566e83557cSMichal Simek addik r1, r1, PT_SIZE /* Clean up stack space */ 8572d5973cbSMichal Simek lwi r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer */ 8582d5973cbSMichal SimekDBTRAP_return_user: /* MS: Make global symbol for debugging */ 8592d5973cbSMichal Simek rtbd r16, 0; /* MS: Instructions to return from a debug trap */ 8602d5973cbSMichal Simek nop; 861ca54502bSMichal Simek 8622d5973cbSMichal Simek/* MS: Return to kernel state - kgdb */ 863ca54502bSMichal Simek2: VM_OFF; 864ca54502bSMichal Simek tophys(r1,r1); 8652d5973cbSMichal Simek /* MS: Restore all regs */ 86614ef905bSMichal Simek RESTORE_REGS_RTBD 8676e83557cSMichal Simek lwi r14, r1, PT_R14; 8686e83557cSMichal Simek lwi r16, r1, PT_PC; 8696e83557cSMichal Simek addik r1, r1, PT_SIZE; /* MS: Clean up stack space */ 870ca54502bSMichal Simek tovirt(r1,r1); 8712d5973cbSMichal SimekDBTRAP_return_kernel: /* MS: Make global symbol for debugging */ 8722d5973cbSMichal Simek rtbd r16, 0; /* MS: Instructions to return from a debug trap */ 873ca54502bSMichal Simek nop; 874ca54502bSMichal Simek 875ca54502bSMichal Simek 876ca54502bSMichal SimekENTRY(_switch_to) 877ca54502bSMichal Simek /* prepare return value */ 878b1d70c62SMichal Simek addk r3, r0, CURRENT_TASK 879ca54502bSMichal Simek 880ca54502bSMichal Simek /* save registers in cpu_context */ 881ca54502bSMichal Simek /* use r11 and r12, volatile registers, as temp register */ 882ca54502bSMichal Simek /* give start of cpu_context for previous process */ 883ca54502bSMichal Simek addik r11, r5, TI_CPU_CONTEXT 884ca54502bSMichal Simek swi r1, r11, CC_R1 885ca54502bSMichal Simek swi r2, r11, CC_R2 886ca54502bSMichal Simek /* skip volatile registers. 887ca54502bSMichal Simek * they are saved on stack when we jumped to _switch_to() */ 888ca54502bSMichal Simek /* dedicated registers */ 889ca54502bSMichal Simek swi r13, r11, CC_R13 890ca54502bSMichal Simek swi r14, r11, CC_R14 891ca54502bSMichal Simek swi r15, r11, CC_R15 892ca54502bSMichal Simek swi r16, r11, CC_R16 893ca54502bSMichal Simek swi r17, r11, CC_R17 894ca54502bSMichal Simek swi r18, r11, CC_R18 895ca54502bSMichal Simek /* save non-volatile registers */ 896ca54502bSMichal Simek swi r19, r11, CC_R19 897ca54502bSMichal Simek swi r20, r11, CC_R20 898ca54502bSMichal Simek swi r21, r11, CC_R21 899ca54502bSMichal Simek swi r22, r11, CC_R22 900ca54502bSMichal Simek swi r23, r11, CC_R23 901ca54502bSMichal Simek swi r24, r11, CC_R24 902ca54502bSMichal Simek swi r25, r11, CC_R25 903ca54502bSMichal Simek swi r26, r11, CC_R26 904ca54502bSMichal Simek swi r27, r11, CC_R27 905ca54502bSMichal Simek swi r28, r11, CC_R28 906ca54502bSMichal Simek swi r29, r11, CC_R29 907ca54502bSMichal Simek swi r30, r11, CC_R30 908ca54502bSMichal Simek /* special purpose registers */ 909ca54502bSMichal Simek mfs r12, rmsr 910ca54502bSMichal Simek swi r12, r11, CC_MSR 911ca54502bSMichal Simek mfs r12, rear 912ca54502bSMichal Simek swi r12, r11, CC_EAR 913ca54502bSMichal Simek mfs r12, resr 914ca54502bSMichal Simek swi r12, r11, CC_ESR 915ca54502bSMichal Simek mfs r12, rfsr 916ca54502bSMichal Simek swi r12, r11, CC_FSR 917ca54502bSMichal Simek 918b1d70c62SMichal Simek /* update r31, the current-give me pointer to task which will be next */ 919b1d70c62SMichal Simek lwi CURRENT_TASK, r6, TI_TASK 920ca54502bSMichal Simek /* stored it to current_save too */ 921b1d70c62SMichal Simek swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE) 922ca54502bSMichal Simek 923ca54502bSMichal Simek /* get new process' cpu context and restore */ 924ca54502bSMichal Simek /* give me start where start context of next task */ 925ca54502bSMichal Simek addik r11, r6, TI_CPU_CONTEXT 926ca54502bSMichal Simek 927ca54502bSMichal Simek /* non-volatile registers */ 928ca54502bSMichal Simek lwi r30, r11, CC_R30 929ca54502bSMichal Simek lwi r29, r11, CC_R29 930ca54502bSMichal Simek lwi r28, r11, CC_R28 931ca54502bSMichal Simek lwi r27, r11, CC_R27 932ca54502bSMichal Simek lwi r26, r11, CC_R26 933ca54502bSMichal Simek lwi r25, r11, CC_R25 934ca54502bSMichal Simek lwi r24, r11, CC_R24 935ca54502bSMichal Simek lwi r23, r11, CC_R23 936ca54502bSMichal Simek lwi r22, r11, CC_R22 937ca54502bSMichal Simek lwi r21, r11, CC_R21 938ca54502bSMichal Simek lwi r20, r11, CC_R20 939ca54502bSMichal Simek lwi r19, r11, CC_R19 940ca54502bSMichal Simek /* dedicated registers */ 941ca54502bSMichal Simek lwi r18, r11, CC_R18 942ca54502bSMichal Simek lwi r17, r11, CC_R17 943ca54502bSMichal Simek lwi r16, r11, CC_R16 944ca54502bSMichal Simek lwi r15, r11, CC_R15 945ca54502bSMichal Simek lwi r14, r11, CC_R14 946ca54502bSMichal Simek lwi r13, r11, CC_R13 947ca54502bSMichal Simek /* skip volatile registers */ 948ca54502bSMichal Simek lwi r2, r11, CC_R2 949ca54502bSMichal Simek lwi r1, r11, CC_R1 950ca54502bSMichal Simek 951ca54502bSMichal Simek /* special purpose registers */ 952ca54502bSMichal Simek lwi r12, r11, CC_FSR 953ca54502bSMichal Simek mts rfsr, r12 954ca54502bSMichal Simek lwi r12, r11, CC_MSR 955ca54502bSMichal Simek mts rmsr, r12 956ca54502bSMichal Simek 957ca54502bSMichal Simek rtsd r15, 8 958ca54502bSMichal Simek nop 959ca54502bSMichal Simek 960*a5e3aaa6SAppana Durga Kedareswara rao#ifdef CONFIG_MB_MANAGER 961*a5e3aaa6SAppana Durga Kedareswara rao.section .data 962*a5e3aaa6SAppana Durga Kedareswara rao.global xmb_manager_dev 963*a5e3aaa6SAppana Durga Kedareswara rao.global xmb_manager_baseaddr 964*a5e3aaa6SAppana Durga Kedareswara rao.global xmb_manager_crval 965*a5e3aaa6SAppana Durga Kedareswara rao.global xmb_manager_callback 966*a5e3aaa6SAppana Durga Kedareswara rao.global xmb_manager_reset_callback 967*a5e3aaa6SAppana Durga Kedareswara rao.align 4 968*a5e3aaa6SAppana Durga Kedareswara raoxmb_manager_dev: 969*a5e3aaa6SAppana Durga Kedareswara rao .long 0 970*a5e3aaa6SAppana Durga Kedareswara raoxmb_manager_baseaddr: 971*a5e3aaa6SAppana Durga Kedareswara rao .long 0 972*a5e3aaa6SAppana Durga Kedareswara raoxmb_manager_crval: 973*a5e3aaa6SAppana Durga Kedareswara rao .long 0 974*a5e3aaa6SAppana Durga Kedareswara raoxmb_manager_callback: 975*a5e3aaa6SAppana Durga Kedareswara rao .long 0 976*a5e3aaa6SAppana Durga Kedareswara raoxmb_manager_reset_callback: 977*a5e3aaa6SAppana Durga Kedareswara rao .long 0 978*a5e3aaa6SAppana Durga Kedareswara rao 979*a5e3aaa6SAppana Durga Kedareswara rao/* 980*a5e3aaa6SAppana Durga Kedareswara rao * When the break vector gets asserted because of error injection, 981*a5e3aaa6SAppana Durga Kedareswara rao * the break signal must be blocked before exiting from the 982*a5e3aaa6SAppana Durga Kedareswara rao * break handler, Below api updates the manager address and 983*a5e3aaa6SAppana Durga Kedareswara rao * control register and error count callback arguments, 984*a5e3aaa6SAppana Durga Kedareswara rao * which will be used by the break handler to block the 985*a5e3aaa6SAppana Durga Kedareswara rao * break and call the callback function. 986*a5e3aaa6SAppana Durga Kedareswara rao */ 987*a5e3aaa6SAppana Durga Kedareswara rao.global xmb_manager_register 988*a5e3aaa6SAppana Durga Kedareswara rao.section .text 989*a5e3aaa6SAppana Durga Kedareswara rao.align 2 990*a5e3aaa6SAppana Durga Kedareswara rao.ent xmb_manager_register 991*a5e3aaa6SAppana Durga Kedareswara rao.type xmb_manager_register, @function 992*a5e3aaa6SAppana Durga Kedareswara raoxmb_manager_register: 993*a5e3aaa6SAppana Durga Kedareswara rao swi r5, r0, xmb_manager_baseaddr 994*a5e3aaa6SAppana Durga Kedareswara rao swi r6, r0, xmb_manager_crval 995*a5e3aaa6SAppana Durga Kedareswara rao swi r7, r0, xmb_manager_callback 996*a5e3aaa6SAppana Durga Kedareswara rao swi r8, r0, xmb_manager_dev 997*a5e3aaa6SAppana Durga Kedareswara rao swi r9, r0, xmb_manager_reset_callback 998*a5e3aaa6SAppana Durga Kedareswara rao 999*a5e3aaa6SAppana Durga Kedareswara rao rtsd r15, 8; 1000*a5e3aaa6SAppana Durga Kedareswara rao nop; 1001*a5e3aaa6SAppana Durga Kedareswara rao.end xmb_manager_register 1002*a5e3aaa6SAppana Durga Kedareswara rao#endif 1003*a5e3aaa6SAppana Durga Kedareswara rao 1004ca54502bSMichal SimekENTRY(_reset) 10055119c418SMichal Simek VM_OFF 10067574349cSMichal Simek brai 0; /* Jump to reset vector */ 1007ca54502bSMichal Simek 1008ca54502bSMichal Simek /* These are compiled and loaded into high memory, then 1009ca54502bSMichal Simek * copied into place in mach_early_setup */ 1010ca54502bSMichal Simek .section .init.ivt, "ax" 10110b9b0200SMichal Simek#if CONFIG_MANUAL_RESET_VECTOR 1012ca54502bSMichal Simek .org 0x0 10130b9b0200SMichal Simek brai CONFIG_MANUAL_RESET_VECTOR 10140b9b0200SMichal Simek#endif 1015626afa35SMichal Simek .org 0x8 1016ca54502bSMichal Simek brai TOPHYS(_user_exception); /* syscall handler */ 1017626afa35SMichal Simek .org 0x10 1018ca54502bSMichal Simek brai TOPHYS(_interrupt); /* Interrupt handler */ 1019626afa35SMichal Simek .org 0x18 1020ca54502bSMichal Simek brai TOPHYS(_debug_exception); /* debug trap handler */ 1021626afa35SMichal Simek .org 0x20 1022751f1605SMichal Simek brai TOPHYS(_hw_exception_handler); /* HW exception handler */ 1023ca54502bSMichal Simek 1024ca54502bSMichal Simek.section .rodata,"a" 1025ca54502bSMichal Simek#include "syscall_table.S" 1026ca54502bSMichal Simek 1027ca54502bSMichal Simeksyscall_table_size=(.-sys_call_table) 1028ca54502bSMichal Simek 1029ce3266c0SSteven J. Magnanitype_SYSCALL: 1030ce3266c0SSteven J. Magnani .ascii "SYSCALL\0" 1031ce3266c0SSteven J. Magnanitype_IRQ: 1032ce3266c0SSteven J. Magnani .ascii "IRQ\0" 1033ce3266c0SSteven J. Magnanitype_IRQ_PREEMPT: 1034ce3266c0SSteven J. Magnani .ascii "IRQ (PREEMPTED)\0" 1035ce3266c0SSteven J. Magnanitype_SYSCALL_PREEMPT: 1036ce3266c0SSteven J. Magnani .ascii " SYSCALL (PREEMPTED)\0" 1037ce3266c0SSteven J. Magnani 1038ce3266c0SSteven J. Magnani /* 1039ce3266c0SSteven J. Magnani * Trap decoding for stack unwinder 1040ce3266c0SSteven J. Magnani * Tuples are (start addr, end addr, string) 1041ce3266c0SSteven J. Magnani * If return address lies on [start addr, end addr], 1042ce3266c0SSteven J. Magnani * unwinder displays 'string' 1043ce3266c0SSteven J. Magnani */ 1044ce3266c0SSteven J. Magnani 1045ce3266c0SSteven J. Magnani .align 4 1046ce3266c0SSteven J. Magnani.global microblaze_trap_handlers 1047ce3266c0SSteven J. Magnanimicroblaze_trap_handlers: 1048ce3266c0SSteven J. Magnani /* Exact matches come first */ 1049ce3266c0SSteven J. Magnani .word ret_from_trap; .word ret_from_trap ; .word type_SYSCALL 1050ce3266c0SSteven J. Magnani .word ret_from_irq ; .word ret_from_irq ; .word type_IRQ 1051ce3266c0SSteven J. Magnani /* Fuzzy matches go here */ 1052ce3266c0SSteven J. Magnani .word ret_from_irq ; .word no_intr_resched ; .word type_IRQ_PREEMPT 1053ce3266c0SSteven J. Magnani .word ret_from_trap; .word TRAP_return ; .word type_SYSCALL_PREEMPT 1054ce3266c0SSteven J. Magnani /* End of table */ 1055ce3266c0SSteven J. Magnani .word 0 ; .word 0 ; .word 0 1056