1*b2441318SGreg Kroah-Hartman/* SPDX-License-Identifier: GPL-2.0 */ 21da177e4SLinus Torvalds/* 31da177e4SLinus Torvalds * This file contains the code that gets mapped at the upper end of each task's text 41da177e4SLinus Torvalds * region. For now, it contains the signal trampoline code only. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Copyright (C) 1999-2003 Hewlett-Packard Co 71da177e4SLinus Torvalds * David Mosberger-Tang <davidm@hpl.hp.com> 81da177e4SLinus Torvalds */ 91da177e4SLinus Torvalds 101da177e4SLinus Torvalds 111da177e4SLinus Torvalds#include <asm/asmmacro.h> 121da177e4SLinus Torvalds#include <asm/errno.h> 1339e01cb8SSam Ravnborg#include <asm/asm-offsets.h> 141da177e4SLinus Torvalds#include <asm/sigcontext.h> 151da177e4SLinus Torvalds#include <asm/unistd.h> 16c140d879SDavid Howells#include <asm/kregs.h> 17c140d879SDavid Howells#include <asm/page.h> 18e55645ecSLuis R. Rodriguez#include <asm/native/inst.h> 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds/* 211da177e4SLinus Torvalds * We can't easily refer to symbols inside the kernel. To avoid full runtime relocation, 221da177e4SLinus Torvalds * complications with the linker (which likes to create PLT stubs for branches 231da177e4SLinus Torvalds * to targets outside the shared object) and to avoid multi-phase kernel builds, we 241da177e4SLinus Torvalds * simply create minimalistic "patch lists" in special ELF sections. 251da177e4SLinus Torvalds */ 26dafb9320SDenys Vlasenko .section ".data..patch.fsyscall_table", "a" 271da177e4SLinus Torvalds .previous 281da177e4SLinus Torvalds#define LOAD_FSYSCALL_TABLE(reg) \ 291da177e4SLinus Torvalds[1:] movl reg=0; \ 30dafb9320SDenys Vlasenko .xdata4 ".data..patch.fsyscall_table", 1b-. 311da177e4SLinus Torvalds 32dafb9320SDenys Vlasenko .section ".data..patch.brl_fsys_bubble_down", "a" 331da177e4SLinus Torvalds .previous 341da177e4SLinus Torvalds#define BRL_COND_FSYS_BUBBLE_DOWN(pr) \ 351da177e4SLinus Torvalds[1:](pr)brl.cond.sptk 0; \ 36c6255e98SChristian Kandeler ;; \ 37dafb9320SDenys Vlasenko .xdata4 ".data..patch.brl_fsys_bubble_down", 1b-. 381da177e4SLinus Torvalds 391da177e4SLinus TorvaldsGLOBAL_ENTRY(__kernel_syscall_via_break) 401da177e4SLinus Torvalds .prologue 411da177e4SLinus Torvalds .altrp b6 421da177e4SLinus Torvalds .body 431da177e4SLinus Torvalds /* 441da177e4SLinus Torvalds * Note: for (fast) syscall restart to work, the break instruction must be 451da177e4SLinus Torvalds * the first one in the bundle addressed by syscall_via_break. 461da177e4SLinus Torvalds */ 471da177e4SLinus Torvalds{ .mib 481da177e4SLinus Torvalds break 0x100000 491da177e4SLinus Torvalds nop.i 0 501da177e4SLinus Torvalds br.ret.sptk.many b6 511da177e4SLinus Torvalds} 521da177e4SLinus TorvaldsEND(__kernel_syscall_via_break) 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds# define ARG0_OFF (16 + IA64_SIGFRAME_ARG0_OFFSET) 551da177e4SLinus Torvalds# define ARG1_OFF (16 + IA64_SIGFRAME_ARG1_OFFSET) 561da177e4SLinus Torvalds# define ARG2_OFF (16 + IA64_SIGFRAME_ARG2_OFFSET) 571da177e4SLinus Torvalds# define SIGHANDLER_OFF (16 + IA64_SIGFRAME_HANDLER_OFFSET) 581da177e4SLinus Torvalds# define SIGCONTEXT_OFF (16 + IA64_SIGFRAME_SIGCONTEXT_OFFSET) 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds# define FLAGS_OFF IA64_SIGCONTEXT_FLAGS_OFFSET 611da177e4SLinus Torvalds# define CFM_OFF IA64_SIGCONTEXT_CFM_OFFSET 621da177e4SLinus Torvalds# define FR6_OFF IA64_SIGCONTEXT_FR6_OFFSET 631da177e4SLinus Torvalds# define BSP_OFF IA64_SIGCONTEXT_AR_BSP_OFFSET 641da177e4SLinus Torvalds# define RNAT_OFF IA64_SIGCONTEXT_AR_RNAT_OFFSET 651da177e4SLinus Torvalds# define UNAT_OFF IA64_SIGCONTEXT_AR_UNAT_OFFSET 661da177e4SLinus Torvalds# define FPSR_OFF IA64_SIGCONTEXT_AR_FPSR_OFFSET 671da177e4SLinus Torvalds# define PR_OFF IA64_SIGCONTEXT_PR_OFFSET 681da177e4SLinus Torvalds# define RP_OFF IA64_SIGCONTEXT_IP_OFFSET 691da177e4SLinus Torvalds# define SP_OFF IA64_SIGCONTEXT_R12_OFFSET 701da177e4SLinus Torvalds# define RBS_BASE_OFF IA64_SIGCONTEXT_RBS_BASE_OFFSET 711da177e4SLinus Torvalds# define LOADRS_OFF IA64_SIGCONTEXT_LOADRS_OFFSET 721da177e4SLinus Torvalds# define base0 r2 731da177e4SLinus Torvalds# define base1 r3 741da177e4SLinus Torvalds /* 751da177e4SLinus Torvalds * When we get here, the memory stack looks like this: 761da177e4SLinus Torvalds * 771da177e4SLinus Torvalds * +===============================+ 781da177e4SLinus Torvalds * | | 791da177e4SLinus Torvalds * // struct sigframe // 801da177e4SLinus Torvalds * | | 811da177e4SLinus Torvalds * +-------------------------------+ <-- sp+16 821da177e4SLinus Torvalds * | 16 byte of scratch | 831da177e4SLinus Torvalds * | space | 841da177e4SLinus Torvalds * +-------------------------------+ <-- sp 851da177e4SLinus Torvalds * 861da177e4SLinus Torvalds * The register stack looks _exactly_ the way it looked at the time the signal 871da177e4SLinus Torvalds * occurred. In other words, we're treading on a potential mine-field: each 881da177e4SLinus Torvalds * incoming general register may be a NaT value (including sp, in which case the 891da177e4SLinus Torvalds * process ends up dying with a SIGSEGV). 901da177e4SLinus Torvalds * 911da177e4SLinus Torvalds * The first thing need to do is a cover to get the registers onto the backing 921da177e4SLinus Torvalds * store. Once that is done, we invoke the signal handler which may modify some 931da177e4SLinus Torvalds * of the machine state. After returning from the signal handler, we return 941da177e4SLinus Torvalds * control to the previous context by executing a sigreturn system call. A signal 951da177e4SLinus Torvalds * handler may call the rt_sigreturn() function to directly return to a given 961da177e4SLinus Torvalds * sigcontext. However, the user-level sigreturn() needs to do much more than 971da177e4SLinus Torvalds * calling the rt_sigreturn() system call as it needs to unwind the stack to 981da177e4SLinus Torvalds * restore preserved registers that may have been saved on the signal handler's 991da177e4SLinus Torvalds * call stack. 1001da177e4SLinus Torvalds */ 1011da177e4SLinus Torvalds 1021da177e4SLinus Torvalds#define SIGTRAMP_SAVES \ 1031da177e4SLinus Torvalds .unwabi 3, 's'; /* mark this as a sigtramp handler (saves scratch regs) */ \ 1041da177e4SLinus Torvalds .unwabi @svr4, 's'; /* backwards compatibility with old unwinders (remove in v2.7) */ \ 1051da177e4SLinus Torvalds .savesp ar.unat, UNAT_OFF+SIGCONTEXT_OFF; \ 1061da177e4SLinus Torvalds .savesp ar.fpsr, FPSR_OFF+SIGCONTEXT_OFF; \ 1071da177e4SLinus Torvalds .savesp pr, PR_OFF+SIGCONTEXT_OFF; \ 1081da177e4SLinus Torvalds .savesp rp, RP_OFF+SIGCONTEXT_OFF; \ 1091da177e4SLinus Torvalds .savesp ar.pfs, CFM_OFF+SIGCONTEXT_OFF; \ 1101da177e4SLinus Torvalds .vframesp SP_OFF+SIGCONTEXT_OFF 1111da177e4SLinus Torvalds 1121da177e4SLinus TorvaldsGLOBAL_ENTRY(__kernel_sigtramp) 1131da177e4SLinus Torvalds // describe the state that is active when we get here: 1141da177e4SLinus Torvalds .prologue 1151da177e4SLinus Torvalds SIGTRAMP_SAVES 1161da177e4SLinus Torvalds .body 1171da177e4SLinus Torvalds 1181da177e4SLinus Torvalds .label_state 1 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds adds base0=SIGHANDLER_OFF,sp 1211da177e4SLinus Torvalds adds base1=RBS_BASE_OFF+SIGCONTEXT_OFF,sp 1221da177e4SLinus Torvalds br.call.sptk.many rp=1f 1231da177e4SLinus Torvalds1: 1241da177e4SLinus Torvalds ld8 r17=[base0],(ARG0_OFF-SIGHANDLER_OFF) // get pointer to signal handler's plabel 1251da177e4SLinus Torvalds ld8 r15=[base1] // get address of new RBS base (or NULL) 1261da177e4SLinus Torvalds cover // push args in interrupted frame onto backing store 1271da177e4SLinus Torvalds ;; 1281da177e4SLinus Torvalds cmp.ne p1,p0=r15,r0 // do we need to switch rbs? (note: pr is saved by kernel) 1291da177e4SLinus Torvalds mov.m r9=ar.bsp // fetch ar.bsp 1301da177e4SLinus Torvalds .spillsp.p p1, ar.rnat, RNAT_OFF+SIGCONTEXT_OFF 1311da177e4SLinus Torvalds(p1) br.cond.spnt setup_rbs // yup -> (clobbers p8, r14-r16, and r18-r20) 1321da177e4SLinus Torvaldsback_from_setup_rbs: 1331da177e4SLinus Torvalds alloc r8=ar.pfs,0,0,3,0 1341da177e4SLinus Torvalds ld8 out0=[base0],16 // load arg0 (signum) 1351da177e4SLinus Torvalds adds base1=(ARG1_OFF-(RBS_BASE_OFF+SIGCONTEXT_OFF)),base1 1361da177e4SLinus Torvalds ;; 1371da177e4SLinus Torvalds ld8 out1=[base1] // load arg1 (siginfop) 1381da177e4SLinus Torvalds ld8 r10=[r17],8 // get signal handler entry point 1391da177e4SLinus Torvalds ;; 1401da177e4SLinus Torvalds ld8 out2=[base0] // load arg2 (sigcontextp) 1411da177e4SLinus Torvalds ld8 gp=[r17] // get signal handler's global pointer 1421da177e4SLinus Torvalds adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp 1431da177e4SLinus Torvalds ;; 1441da177e4SLinus Torvalds .spillsp ar.bsp, BSP_OFF+SIGCONTEXT_OFF 1451da177e4SLinus Torvalds st8 [base0]=r9 // save sc_ar_bsp 1461da177e4SLinus Torvalds adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp 1471da177e4SLinus Torvalds adds base1=(FR6_OFF+16+SIGCONTEXT_OFF),sp 1481da177e4SLinus Torvalds ;; 1491da177e4SLinus Torvalds stf.spill [base0]=f6,32 1501da177e4SLinus Torvalds stf.spill [base1]=f7,32 1511da177e4SLinus Torvalds ;; 1521da177e4SLinus Torvalds stf.spill [base0]=f8,32 1531da177e4SLinus Torvalds stf.spill [base1]=f9,32 1541da177e4SLinus Torvalds mov b6=r10 1551da177e4SLinus Torvalds ;; 1561da177e4SLinus Torvalds stf.spill [base0]=f10,32 1571da177e4SLinus Torvalds stf.spill [base1]=f11,32 1581da177e4SLinus Torvalds ;; 1591da177e4SLinus Torvalds stf.spill [base0]=f12,32 1601da177e4SLinus Torvalds stf.spill [base1]=f13,32 1611da177e4SLinus Torvalds ;; 1621da177e4SLinus Torvalds stf.spill [base0]=f14,32 1631da177e4SLinus Torvalds stf.spill [base1]=f15,32 1641da177e4SLinus Torvalds br.call.sptk.many rp=b6 // call the signal handler 1651da177e4SLinus Torvalds.ret0: adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp 1661da177e4SLinus Torvalds ;; 1671da177e4SLinus Torvalds ld8 r15=[base0] // fetch sc_ar_bsp 1681da177e4SLinus Torvalds mov r14=ar.bsp 1691da177e4SLinus Torvalds ;; 1701da177e4SLinus Torvalds cmp.ne p1,p0=r14,r15 // do we need to restore the rbs? 1711da177e4SLinus Torvalds(p1) br.cond.spnt restore_rbs // yup -> (clobbers r14-r18, f6 & f7) 1721da177e4SLinus Torvalds ;; 1731da177e4SLinus Torvaldsback_from_restore_rbs: 1741da177e4SLinus Torvalds adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp 1751da177e4SLinus Torvalds adds base1=(FR6_OFF+16+SIGCONTEXT_OFF),sp 1761da177e4SLinus Torvalds ;; 1771da177e4SLinus Torvalds ldf.fill f6=[base0],32 1781da177e4SLinus Torvalds ldf.fill f7=[base1],32 1791da177e4SLinus Torvalds ;; 1801da177e4SLinus Torvalds ldf.fill f8=[base0],32 1811da177e4SLinus Torvalds ldf.fill f9=[base1],32 1821da177e4SLinus Torvalds ;; 1831da177e4SLinus Torvalds ldf.fill f10=[base0],32 1841da177e4SLinus Torvalds ldf.fill f11=[base1],32 1851da177e4SLinus Torvalds ;; 1861da177e4SLinus Torvalds ldf.fill f12=[base0],32 1871da177e4SLinus Torvalds ldf.fill f13=[base1],32 1881da177e4SLinus Torvalds ;; 1891da177e4SLinus Torvalds ldf.fill f14=[base0],32 1901da177e4SLinus Torvalds ldf.fill f15=[base1],32 1911da177e4SLinus Torvalds mov r15=__NR_rt_sigreturn 1921da177e4SLinus Torvalds .restore sp // pop .prologue 1931da177e4SLinus Torvalds break __BREAK_SYSCALL 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds .prologue 1961da177e4SLinus Torvalds SIGTRAMP_SAVES 1971da177e4SLinus Torvaldssetup_rbs: 1981da177e4SLinus Torvalds mov ar.rsc=0 // put RSE into enforced lazy mode 1991da177e4SLinus Torvalds ;; 2001da177e4SLinus Torvalds .save ar.rnat, r19 2011da177e4SLinus Torvalds mov r19=ar.rnat // save RNaT before switching backing store area 2021da177e4SLinus Torvalds adds r14=(RNAT_OFF+SIGCONTEXT_OFF),sp 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds mov r18=ar.bspstore 2051da177e4SLinus Torvalds mov ar.bspstore=r15 // switch over to new register backing store area 2061da177e4SLinus Torvalds ;; 2071da177e4SLinus Torvalds 2081da177e4SLinus Torvalds .spillsp ar.rnat, RNAT_OFF+SIGCONTEXT_OFF 2091da177e4SLinus Torvalds st8 [r14]=r19 // save sc_ar_rnat 2101da177e4SLinus Torvalds .body 2111da177e4SLinus Torvalds mov.m r16=ar.bsp // sc_loadrs <- (new bsp - new bspstore) << 16 2121da177e4SLinus Torvalds adds r14=(LOADRS_OFF+SIGCONTEXT_OFF),sp 2131da177e4SLinus Torvalds ;; 2141da177e4SLinus Torvalds invala 2151da177e4SLinus Torvalds sub r15=r16,r15 2161da177e4SLinus Torvalds extr.u r20=r18,3,6 2171da177e4SLinus Torvalds ;; 2181da177e4SLinus Torvalds mov ar.rsc=0xf // set RSE into eager mode, pl 3 2191da177e4SLinus Torvalds cmp.eq p8,p0=63,r20 2201da177e4SLinus Torvalds shl r15=r15,16 2211da177e4SLinus Torvalds ;; 2221da177e4SLinus Torvalds st8 [r14]=r15 // save sc_loadrs 2231da177e4SLinus Torvalds(p8) st8 [r18]=r19 // if bspstore points at RNaT slot, store RNaT there now 2241da177e4SLinus Torvalds .restore sp // pop .prologue 2251da177e4SLinus Torvalds br.cond.sptk back_from_setup_rbs 2261da177e4SLinus Torvalds 2271da177e4SLinus Torvalds .prologue 2281da177e4SLinus Torvalds SIGTRAMP_SAVES 2291da177e4SLinus Torvalds .spillsp ar.rnat, RNAT_OFF+SIGCONTEXT_OFF 2301da177e4SLinus Torvalds .body 2311da177e4SLinus Torvaldsrestore_rbs: 2321da177e4SLinus Torvalds // On input: 2331da177e4SLinus Torvalds // r14 = bsp1 (bsp at the time of return from signal handler) 2341da177e4SLinus Torvalds // r15 = bsp0 (bsp at the time the signal occurred) 2351da177e4SLinus Torvalds // 2361da177e4SLinus Torvalds // Here, we need to calculate bspstore0, the value that ar.bspstore needs 2371da177e4SLinus Torvalds // to be set to, based on bsp0 and the size of the dirty partition on 2381da177e4SLinus Torvalds // the alternate stack (sc_loadrs >> 16). This can be done with the 2391da177e4SLinus Torvalds // following algorithm: 2401da177e4SLinus Torvalds // 2411da177e4SLinus Torvalds // bspstore0 = rse_skip_regs(bsp0, -rse_num_regs(bsp1 - (loadrs >> 19), bsp1)); 2421da177e4SLinus Torvalds // 2431da177e4SLinus Torvalds // This is what the code below does. 2441da177e4SLinus Torvalds // 2451da177e4SLinus Torvalds alloc r2=ar.pfs,0,0,0,0 // alloc null frame 2461da177e4SLinus Torvalds adds r16=(LOADRS_OFF+SIGCONTEXT_OFF),sp 2471da177e4SLinus Torvalds adds r18=(RNAT_OFF+SIGCONTEXT_OFF),sp 2481da177e4SLinus Torvalds ;; 2491da177e4SLinus Torvalds ld8 r17=[r16] 2501da177e4SLinus Torvalds ld8 r16=[r18] // get new rnat 2511da177e4SLinus Torvalds extr.u r18=r15,3,6 // r18 <- rse_slot_num(bsp0) 2521da177e4SLinus Torvalds ;; 2531da177e4SLinus Torvalds mov ar.rsc=r17 // put RSE into enforced lazy mode 2541da177e4SLinus Torvalds shr.u r17=r17,16 2551da177e4SLinus Torvalds ;; 2561da177e4SLinus Torvalds sub r14=r14,r17 // r14 (bspstore1) <- bsp1 - (sc_loadrs >> 16) 2571da177e4SLinus Torvalds shr.u r17=r17,3 // r17 <- (sc_loadrs >> 19) 2581da177e4SLinus Torvalds ;; 2591da177e4SLinus Torvalds loadrs // restore dirty partition 2601da177e4SLinus Torvalds extr.u r14=r14,3,6 // r14 <- rse_slot_num(bspstore1) 2611da177e4SLinus Torvalds ;; 2621da177e4SLinus Torvalds add r14=r14,r17 // r14 <- rse_slot_num(bspstore1) + (sc_loadrs >> 19) 2631da177e4SLinus Torvalds ;; 2641da177e4SLinus Torvalds shr.u r14=r14,6 // r14 <- (rse_slot_num(bspstore1) + (sc_loadrs >> 19))/0x40 2651da177e4SLinus Torvalds ;; 2661da177e4SLinus Torvalds sub r14=r14,r17 // r14 <- -rse_num_regs(bspstore1, bsp1) 2671da177e4SLinus Torvalds movl r17=0x8208208208208209 2681da177e4SLinus Torvalds ;; 2691da177e4SLinus Torvalds add r18=r18,r14 // r18 (delta) <- rse_slot_num(bsp0) - rse_num_regs(bspstore1,bsp1) 2701da177e4SLinus Torvalds setf.sig f7=r17 2711da177e4SLinus Torvalds cmp.lt p7,p0=r14,r0 // p7 <- (r14 < 0)? 2721da177e4SLinus Torvalds ;; 2731da177e4SLinus Torvalds(p7) adds r18=-62,r18 // delta -= 62 2741da177e4SLinus Torvalds ;; 2751da177e4SLinus Torvalds setf.sig f6=r18 2761da177e4SLinus Torvalds ;; 2771da177e4SLinus Torvalds xmpy.h f6=f6,f7 2781da177e4SLinus Torvalds ;; 2791da177e4SLinus Torvalds getf.sig r17=f6 2801da177e4SLinus Torvalds ;; 2811da177e4SLinus Torvalds add r17=r17,r18 2821da177e4SLinus Torvalds shr r18=r18,63 2831da177e4SLinus Torvalds ;; 2841da177e4SLinus Torvalds shr r17=r17,5 2851da177e4SLinus Torvalds ;; 2861da177e4SLinus Torvalds sub r17=r17,r18 // r17 = delta/63 2871da177e4SLinus Torvalds ;; 2881da177e4SLinus Torvalds add r17=r14,r17 // r17 <- delta/63 - rse_num_regs(bspstore1, bsp1) 2891da177e4SLinus Torvalds ;; 2901da177e4SLinus Torvalds shladd r15=r17,3,r15 // r15 <- bsp0 + 8*(delta/63 - rse_num_regs(bspstore1, bsp1)) 2911da177e4SLinus Torvalds ;; 2921da177e4SLinus Torvalds mov ar.bspstore=r15 // switch back to old register backing store area 2931da177e4SLinus Torvalds ;; 2941da177e4SLinus Torvalds mov ar.rnat=r16 // restore RNaT 2951da177e4SLinus Torvalds mov ar.rsc=0xf // (will be restored later on from sc_ar_rsc) 2961da177e4SLinus Torvalds // invala not necessary as that will happen when returning to user-mode 2971da177e4SLinus Torvalds br.cond.sptk back_from_restore_rbs 2981da177e4SLinus TorvaldsEND(__kernel_sigtramp) 29953129c5cSIsaku Yamahata 30053129c5cSIsaku Yamahata/* 30153129c5cSIsaku Yamahata * On entry: 30253129c5cSIsaku Yamahata * r11 = saved ar.pfs 30353129c5cSIsaku Yamahata * r15 = system call # 30453129c5cSIsaku Yamahata * b0 = saved return address 30553129c5cSIsaku Yamahata * b6 = return address 30653129c5cSIsaku Yamahata * On exit: 30753129c5cSIsaku Yamahata * r11 = saved ar.pfs 30853129c5cSIsaku Yamahata * r15 = system call # 30953129c5cSIsaku Yamahata * b0 = saved return address 31053129c5cSIsaku Yamahata * all other "scratch" registers: undefined 31153129c5cSIsaku Yamahata * all "preserved" registers: same as on entry 31253129c5cSIsaku Yamahata */ 31353129c5cSIsaku Yamahata 31453129c5cSIsaku YamahataGLOBAL_ENTRY(__kernel_syscall_via_epc) 31553129c5cSIsaku Yamahata .prologue 31653129c5cSIsaku Yamahata .altrp b6 31753129c5cSIsaku Yamahata .body 31853129c5cSIsaku Yamahata{ 31953129c5cSIsaku Yamahata /* 32053129c5cSIsaku Yamahata * Note: the kernel cannot assume that the first two instructions in this 32153129c5cSIsaku Yamahata * bundle get executed. The remaining code must be safe even if 32253129c5cSIsaku Yamahata * they do not get executed. 32353129c5cSIsaku Yamahata */ 32453129c5cSIsaku Yamahata adds r17=-1024,r15 // A 32553129c5cSIsaku Yamahata mov r10=0 // A default to successful syscall execution 32653129c5cSIsaku Yamahata epc // B causes split-issue 32753129c5cSIsaku Yamahata} 32853129c5cSIsaku Yamahata ;; 329c4312511SIsaku Yamahata RSM_PSR_BE_I(r20, r22) // M2 (5 cyc to srlz.d) 33053129c5cSIsaku Yamahata LOAD_FSYSCALL_TABLE(r14) // X 33153129c5cSIsaku Yamahata ;; 33253129c5cSIsaku Yamahata mov r16=IA64_KR(CURRENT) // M2 (12 cyc) 33353129c5cSIsaku Yamahata shladd r18=r17,3,r14 // A 33453129c5cSIsaku Yamahata mov r19=NR_syscalls-1 // A 33553129c5cSIsaku Yamahata ;; 33653129c5cSIsaku Yamahata lfetch [r18] // M0|1 337c4312511SIsaku Yamahata MOV_FROM_PSR(p0, r29, r8) // M2 (12 cyc) 33853129c5cSIsaku Yamahata // If r17 is a NaT, p6 will be zero 33953129c5cSIsaku Yamahata cmp.geu p6,p7=r19,r17 // A (sysnr > 0 && sysnr < 1024+NR_syscalls)? 34053129c5cSIsaku Yamahata ;; 34153129c5cSIsaku Yamahata mov r21=ar.fpsr // M2 (12 cyc) 34253129c5cSIsaku Yamahata tnat.nz p10,p9=r15 // I0 34353129c5cSIsaku Yamahata mov.i r26=ar.pfs // I0 (would stall anyhow due to srlz.d...) 34453129c5cSIsaku Yamahata ;; 34553129c5cSIsaku Yamahata srlz.d // M0 (forces split-issue) ensure PSR.BE==0 34653129c5cSIsaku Yamahata(p6) ld8 r18=[r18] // M0|1 34753129c5cSIsaku Yamahata nop.i 0 34853129c5cSIsaku Yamahata ;; 34953129c5cSIsaku Yamahata nop.m 0 35053129c5cSIsaku Yamahata(p6) tbit.z.unc p8,p0=r18,0 // I0 (dual-issues with "mov b7=r18"!) 35153129c5cSIsaku Yamahata nop.i 0 35253129c5cSIsaku Yamahata ;; 353c4312511SIsaku Yamahata SSM_PSR_I(p8, p14, r25) 35453129c5cSIsaku Yamahata(p6) mov b7=r18 // I0 35553129c5cSIsaku Yamahata(p8) br.dptk.many b7 // B 35653129c5cSIsaku Yamahata 35753129c5cSIsaku Yamahata mov r27=ar.rsc // M2 (12 cyc) 35853129c5cSIsaku Yamahata/* 35953129c5cSIsaku Yamahata * brl.cond doesn't work as intended because the linker would convert this branch 36053129c5cSIsaku Yamahata * into a branch to a PLT. Perhaps there will be a way to avoid this with some 36153129c5cSIsaku Yamahata * future version of the linker. In the meantime, we just use an indirect branch 36253129c5cSIsaku Yamahata * instead. 36353129c5cSIsaku Yamahata */ 36453129c5cSIsaku Yamahata#ifdef CONFIG_ITANIUM 36553129c5cSIsaku Yamahata(p6) add r14=-8,r14 // r14 <- addr of fsys_bubble_down entry 36653129c5cSIsaku Yamahata ;; 36753129c5cSIsaku Yamahata(p6) ld8 r14=[r14] // r14 <- fsys_bubble_down 36853129c5cSIsaku Yamahata ;; 36953129c5cSIsaku Yamahata(p6) mov b7=r14 37053129c5cSIsaku Yamahata(p6) br.sptk.many b7 37153129c5cSIsaku Yamahata#else 37253129c5cSIsaku Yamahata BRL_COND_FSYS_BUBBLE_DOWN(p6) 37353129c5cSIsaku Yamahata#endif 374c4312511SIsaku Yamahata SSM_PSR_I(p0, p14, r10) 37553129c5cSIsaku Yamahata mov r10=-1 37653129c5cSIsaku Yamahata(p10) mov r8=EINVAL 37753129c5cSIsaku Yamahata(p9) mov r8=ENOSYS 37853129c5cSIsaku Yamahata FSYS_RETURN 379c4312511SIsaku Yamahata 38053129c5cSIsaku YamahataEND(__kernel_syscall_via_epc) 381