18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * arch/ia64/kernel/entry.S 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Kernel entry points. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 1998-2003, 2005 Hewlett-Packard Co 88c2ecf20Sopenharmony_ci * David Mosberger-Tang <davidm@hpl.hp.com> 98c2ecf20Sopenharmony_ci * Copyright (C) 1999, 2002-2003 108c2ecf20Sopenharmony_ci * Asit Mallick <Asit.K.Mallick@intel.com> 118c2ecf20Sopenharmony_ci * Don Dugger <Don.Dugger@intel.com> 128c2ecf20Sopenharmony_ci * Suresh Siddha <suresh.b.siddha@intel.com> 138c2ecf20Sopenharmony_ci * Fenghua Yu <fenghua.yu@intel.com> 148c2ecf20Sopenharmony_ci * Copyright (C) 1999 VA Linux Systems 158c2ecf20Sopenharmony_ci * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci/* 188c2ecf20Sopenharmony_ci * ia64_switch_to now places correct virtual mapping in in TR2 for 198c2ecf20Sopenharmony_ci * kernel stack. This allows us to handle interrupts without changing 208c2ecf20Sopenharmony_ci * to physical mode. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Jonathan Nicklin <nicklin@missioncriticallinux.com> 238c2ecf20Sopenharmony_ci * Patrick O'Rourke <orourke@missioncriticallinux.com> 248c2ecf20Sopenharmony_ci * 11/07/2000 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_ci/* 278c2ecf20Sopenharmony_ci * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp> 288c2ecf20Sopenharmony_ci * VA Linux Systems Japan K.K. 298c2ecf20Sopenharmony_ci * pv_ops. 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_ci/* 328c2ecf20Sopenharmony_ci * Global (preserved) predicate usage on syscall entry/exit path: 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci * pKStk: See entry.h. 358c2ecf20Sopenharmony_ci * pUStk: See entry.h. 368c2ecf20Sopenharmony_ci * pSys: See entry.h. 378c2ecf20Sopenharmony_ci * pNonSys: !pSys 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#include <linux/pgtable.h> 428c2ecf20Sopenharmony_ci#include <asm/asmmacro.h> 438c2ecf20Sopenharmony_ci#include <asm/cache.h> 448c2ecf20Sopenharmony_ci#include <asm/errno.h> 458c2ecf20Sopenharmony_ci#include <asm/kregs.h> 468c2ecf20Sopenharmony_ci#include <asm/asm-offsets.h> 478c2ecf20Sopenharmony_ci#include <asm/percpu.h> 488c2ecf20Sopenharmony_ci#include <asm/processor.h> 498c2ecf20Sopenharmony_ci#include <asm/thread_info.h> 508c2ecf20Sopenharmony_ci#include <asm/unistd.h> 518c2ecf20Sopenharmony_ci#include <asm/ftrace.h> 528c2ecf20Sopenharmony_ci#include <asm/export.h> 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#include "minstate.h" 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci /* 578c2ecf20Sopenharmony_ci * execve() is special because in case of success, we need to 588c2ecf20Sopenharmony_ci * setup a null register window frame. 598c2ecf20Sopenharmony_ci */ 608c2ecf20Sopenharmony_ciENTRY(ia64_execve) 618c2ecf20Sopenharmony_ci /* 628c2ecf20Sopenharmony_ci * Allocate 8 input registers since ptrace() may clobber them 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_ci .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) 658c2ecf20Sopenharmony_ci alloc loc1=ar.pfs,8,2,3,0 668c2ecf20Sopenharmony_ci mov loc0=rp 678c2ecf20Sopenharmony_ci .body 688c2ecf20Sopenharmony_ci mov out0=in0 // filename 698c2ecf20Sopenharmony_ci ;; // stop bit between alloc and call 708c2ecf20Sopenharmony_ci mov out1=in1 // argv 718c2ecf20Sopenharmony_ci mov out2=in2 // envp 728c2ecf20Sopenharmony_ci br.call.sptk.many rp=sys_execve 738c2ecf20Sopenharmony_ci.ret0: 748c2ecf20Sopenharmony_ci cmp4.ge p6,p7=r8,r0 758c2ecf20Sopenharmony_ci mov ar.pfs=loc1 // restore ar.pfs 768c2ecf20Sopenharmony_ci sxt4 r8=r8 // return 64-bit result 778c2ecf20Sopenharmony_ci ;; 788c2ecf20Sopenharmony_ci stf.spill [sp]=f0 798c2ecf20Sopenharmony_ci mov rp=loc0 808c2ecf20Sopenharmony_ci(p6) mov ar.pfs=r0 // clear ar.pfs on success 818c2ecf20Sopenharmony_ci(p7) br.ret.sptk.many rp 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci /* 848c2ecf20Sopenharmony_ci * In theory, we'd have to zap this state only to prevent leaking of 858c2ecf20Sopenharmony_ci * security sensitive state (e.g., if current->mm->dumpable is zero). However, 868c2ecf20Sopenharmony_ci * this executes in less than 20 cycles even on Itanium, so it's not worth 878c2ecf20Sopenharmony_ci * optimizing for...). 888c2ecf20Sopenharmony_ci */ 898c2ecf20Sopenharmony_ci mov ar.unat=0; mov ar.lc=0 908c2ecf20Sopenharmony_ci mov r4=0; mov f2=f0; mov b1=r0 918c2ecf20Sopenharmony_ci mov r5=0; mov f3=f0; mov b2=r0 928c2ecf20Sopenharmony_ci mov r6=0; mov f4=f0; mov b3=r0 938c2ecf20Sopenharmony_ci mov r7=0; mov f5=f0; mov b4=r0 948c2ecf20Sopenharmony_ci ldf.fill f12=[sp]; mov f13=f0; mov b5=r0 958c2ecf20Sopenharmony_ci ldf.fill f14=[sp]; ldf.fill f15=[sp]; mov f16=f0 968c2ecf20Sopenharmony_ci ldf.fill f17=[sp]; ldf.fill f18=[sp]; mov f19=f0 978c2ecf20Sopenharmony_ci ldf.fill f20=[sp]; ldf.fill f21=[sp]; mov f22=f0 988c2ecf20Sopenharmony_ci ldf.fill f23=[sp]; ldf.fill f24=[sp]; mov f25=f0 998c2ecf20Sopenharmony_ci ldf.fill f26=[sp]; ldf.fill f27=[sp]; mov f28=f0 1008c2ecf20Sopenharmony_ci ldf.fill f29=[sp]; ldf.fill f30=[sp]; mov f31=f0 1018c2ecf20Sopenharmony_ci br.ret.sptk.many rp 1028c2ecf20Sopenharmony_ciEND(ia64_execve) 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/* 1058c2ecf20Sopenharmony_ci * sys_clone2(u64 flags, u64 ustack_base, u64 ustack_size, u64 parent_tidptr, u64 child_tidptr, 1068c2ecf20Sopenharmony_ci * u64 tls) 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_ciGLOBAL_ENTRY(sys_clone2) 1098c2ecf20Sopenharmony_ci /* 1108c2ecf20Sopenharmony_ci * Allocate 8 input registers since ptrace() may clobber them 1118c2ecf20Sopenharmony_ci */ 1128c2ecf20Sopenharmony_ci .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) 1138c2ecf20Sopenharmony_ci alloc r16=ar.pfs,8,2,6,0 1148c2ecf20Sopenharmony_ci DO_SAVE_SWITCH_STACK 1158c2ecf20Sopenharmony_ci mov loc0=rp 1168c2ecf20Sopenharmony_ci mov loc1=r16 // save ar.pfs across ia64_clone 1178c2ecf20Sopenharmony_ci .body 1188c2ecf20Sopenharmony_ci mov out0=in0 1198c2ecf20Sopenharmony_ci mov out1=in1 1208c2ecf20Sopenharmony_ci mov out2=in2 1218c2ecf20Sopenharmony_ci mov out3=in3 1228c2ecf20Sopenharmony_ci mov out4=in4 1238c2ecf20Sopenharmony_ci mov out5=in5 1248c2ecf20Sopenharmony_ci br.call.sptk.many rp=ia64_clone 1258c2ecf20Sopenharmony_ci.ret1: .restore sp 1268c2ecf20Sopenharmony_ci adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack 1278c2ecf20Sopenharmony_ci mov ar.pfs=loc1 1288c2ecf20Sopenharmony_ci mov rp=loc0 1298c2ecf20Sopenharmony_ci br.ret.sptk.many rp 1308c2ecf20Sopenharmony_ciEND(sys_clone2) 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci/* 1338c2ecf20Sopenharmony_ci * sys_clone(u64 flags, u64 ustack_base, u64 parent_tidptr, u64 child_tidptr, u64 tls) 1348c2ecf20Sopenharmony_ci * Deprecated. Use sys_clone2() instead. 1358c2ecf20Sopenharmony_ci */ 1368c2ecf20Sopenharmony_ciGLOBAL_ENTRY(sys_clone) 1378c2ecf20Sopenharmony_ci /* 1388c2ecf20Sopenharmony_ci * Allocate 8 input registers since ptrace() may clobber them 1398c2ecf20Sopenharmony_ci */ 1408c2ecf20Sopenharmony_ci .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) 1418c2ecf20Sopenharmony_ci alloc r16=ar.pfs,8,2,6,0 1428c2ecf20Sopenharmony_ci DO_SAVE_SWITCH_STACK 1438c2ecf20Sopenharmony_ci mov loc0=rp 1448c2ecf20Sopenharmony_ci mov loc1=r16 // save ar.pfs across ia64_clone 1458c2ecf20Sopenharmony_ci .body 1468c2ecf20Sopenharmony_ci mov out0=in0 1478c2ecf20Sopenharmony_ci mov out1=in1 1488c2ecf20Sopenharmony_ci mov out2=16 // stacksize (compensates for 16-byte scratch area) 1498c2ecf20Sopenharmony_ci mov out3=in3 1508c2ecf20Sopenharmony_ci mov out4=in4 1518c2ecf20Sopenharmony_ci mov out5=in5 1528c2ecf20Sopenharmony_ci br.call.sptk.many rp=ia64_clone 1538c2ecf20Sopenharmony_ci.ret2: .restore sp 1548c2ecf20Sopenharmony_ci adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack 1558c2ecf20Sopenharmony_ci mov ar.pfs=loc1 1568c2ecf20Sopenharmony_ci mov rp=loc0 1578c2ecf20Sopenharmony_ci br.ret.sptk.many rp 1588c2ecf20Sopenharmony_ciEND(sys_clone) 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci/* 1618c2ecf20Sopenharmony_ci * prev_task <- ia64_switch_to(struct task_struct *next) 1628c2ecf20Sopenharmony_ci * With Ingo's new scheduler, interrupts are disabled when this routine gets 1638c2ecf20Sopenharmony_ci * called. The code starting at .map relies on this. The rest of the code 1648c2ecf20Sopenharmony_ci * doesn't care about the interrupt masking status. 1658c2ecf20Sopenharmony_ci */ 1668c2ecf20Sopenharmony_ciGLOBAL_ENTRY(ia64_switch_to) 1678c2ecf20Sopenharmony_ci .prologue 1688c2ecf20Sopenharmony_ci alloc r16=ar.pfs,1,0,0,0 1698c2ecf20Sopenharmony_ci DO_SAVE_SWITCH_STACK 1708c2ecf20Sopenharmony_ci .body 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci adds r22=IA64_TASK_THREAD_KSP_OFFSET,r13 1738c2ecf20Sopenharmony_ci movl r25=init_task 1748c2ecf20Sopenharmony_ci mov r27=IA64_KR(CURRENT_STACK) 1758c2ecf20Sopenharmony_ci adds r21=IA64_TASK_THREAD_KSP_OFFSET,in0 1768c2ecf20Sopenharmony_ci dep r20=0,in0,61,3 // physical address of "next" 1778c2ecf20Sopenharmony_ci ;; 1788c2ecf20Sopenharmony_ci st8 [r22]=sp // save kernel stack pointer of old task 1798c2ecf20Sopenharmony_ci shr.u r26=r20,IA64_GRANULE_SHIFT 1808c2ecf20Sopenharmony_ci cmp.eq p7,p6=r25,in0 1818c2ecf20Sopenharmony_ci ;; 1828c2ecf20Sopenharmony_ci /* 1838c2ecf20Sopenharmony_ci * If we've already mapped this task's page, we can skip doing it again. 1848c2ecf20Sopenharmony_ci */ 1858c2ecf20Sopenharmony_ci(p6) cmp.eq p7,p6=r26,r27 1868c2ecf20Sopenharmony_ci(p6) br.cond.dpnt .map 1878c2ecf20Sopenharmony_ci ;; 1888c2ecf20Sopenharmony_ci.done: 1898c2ecf20Sopenharmony_ci ld8 sp=[r21] // load kernel stack pointer of new task 1908c2ecf20Sopenharmony_ci MOV_TO_KR(CURRENT, in0, r8, r9) // update "current" application register 1918c2ecf20Sopenharmony_ci mov r8=r13 // return pointer to previously running task 1928c2ecf20Sopenharmony_ci mov r13=in0 // set "current" pointer 1938c2ecf20Sopenharmony_ci ;; 1948c2ecf20Sopenharmony_ci DO_LOAD_SWITCH_STACK 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP 1978c2ecf20Sopenharmony_ci sync.i // ensure "fc"s done by this CPU are visible on other CPUs 1988c2ecf20Sopenharmony_ci#endif 1998c2ecf20Sopenharmony_ci br.ret.sptk.many rp // boogie on out in new context 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci.map: 2028c2ecf20Sopenharmony_ci RSM_PSR_IC(r25) // interrupts (psr.i) are already disabled here 2038c2ecf20Sopenharmony_ci movl r25=PAGE_KERNEL 2048c2ecf20Sopenharmony_ci ;; 2058c2ecf20Sopenharmony_ci srlz.d 2068c2ecf20Sopenharmony_ci or r23=r25,r20 // construct PA | page properties 2078c2ecf20Sopenharmony_ci mov r25=IA64_GRANULE_SHIFT<<2 2088c2ecf20Sopenharmony_ci ;; 2098c2ecf20Sopenharmony_ci MOV_TO_ITIR(p0, r25, r8) 2108c2ecf20Sopenharmony_ci MOV_TO_IFA(in0, r8) // VA of next task... 2118c2ecf20Sopenharmony_ci ;; 2128c2ecf20Sopenharmony_ci mov r25=IA64_TR_CURRENT_STACK 2138c2ecf20Sopenharmony_ci MOV_TO_KR(CURRENT_STACK, r26, r8, r9) // remember last page we mapped... 2148c2ecf20Sopenharmony_ci ;; 2158c2ecf20Sopenharmony_ci itr.d dtr[r25]=r23 // wire in new mapping... 2168c2ecf20Sopenharmony_ci SSM_PSR_IC_AND_SRLZ_D(r8, r9) // reenable the psr.ic bit 2178c2ecf20Sopenharmony_ci br.cond.sptk .done 2188c2ecf20Sopenharmony_ciEND(ia64_switch_to) 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci/* 2218c2ecf20Sopenharmony_ci * Note that interrupts are enabled during save_switch_stack and load_switch_stack. This 2228c2ecf20Sopenharmony_ci * means that we may get an interrupt with "sp" pointing to the new kernel stack while 2238c2ecf20Sopenharmony_ci * ar.bspstore is still pointing to the old kernel backing store area. Since ar.rsc, 2248c2ecf20Sopenharmony_ci * ar.rnat, ar.bsp, and ar.bspstore are all preserved by interrupts, this is not a 2258c2ecf20Sopenharmony_ci * problem. Also, we don't need to specify unwind information for preserved registers 2268c2ecf20Sopenharmony_ci * that are not modified in save_switch_stack as the right unwind information is already 2278c2ecf20Sopenharmony_ci * specified at the call-site of save_switch_stack. 2288c2ecf20Sopenharmony_ci */ 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci/* 2318c2ecf20Sopenharmony_ci * save_switch_stack: 2328c2ecf20Sopenharmony_ci * - r16 holds ar.pfs 2338c2ecf20Sopenharmony_ci * - b7 holds address to return to 2348c2ecf20Sopenharmony_ci * - rp (b0) holds return address to save 2358c2ecf20Sopenharmony_ci */ 2368c2ecf20Sopenharmony_ciGLOBAL_ENTRY(save_switch_stack) 2378c2ecf20Sopenharmony_ci .prologue 2388c2ecf20Sopenharmony_ci .altrp b7 2398c2ecf20Sopenharmony_ci flushrs // flush dirty regs to backing store (must be first in insn group) 2408c2ecf20Sopenharmony_ci .save @priunat,r17 2418c2ecf20Sopenharmony_ci mov r17=ar.unat // preserve caller's 2428c2ecf20Sopenharmony_ci .body 2438c2ecf20Sopenharmony_ci#ifdef CONFIG_ITANIUM 2448c2ecf20Sopenharmony_ci adds r2=16+128,sp 2458c2ecf20Sopenharmony_ci adds r3=16+64,sp 2468c2ecf20Sopenharmony_ci adds r14=SW(R4)+16,sp 2478c2ecf20Sopenharmony_ci ;; 2488c2ecf20Sopenharmony_ci st8.spill [r14]=r4,16 // spill r4 2498c2ecf20Sopenharmony_ci lfetch.fault.excl.nt1 [r3],128 2508c2ecf20Sopenharmony_ci ;; 2518c2ecf20Sopenharmony_ci lfetch.fault.excl.nt1 [r2],128 2528c2ecf20Sopenharmony_ci lfetch.fault.excl.nt1 [r3],128 2538c2ecf20Sopenharmony_ci ;; 2548c2ecf20Sopenharmony_ci lfetch.fault.excl [r2] 2558c2ecf20Sopenharmony_ci lfetch.fault.excl [r3] 2568c2ecf20Sopenharmony_ci adds r15=SW(R5)+16,sp 2578c2ecf20Sopenharmony_ci#else 2588c2ecf20Sopenharmony_ci add r2=16+3*128,sp 2598c2ecf20Sopenharmony_ci add r3=16,sp 2608c2ecf20Sopenharmony_ci add r14=SW(R4)+16,sp 2618c2ecf20Sopenharmony_ci ;; 2628c2ecf20Sopenharmony_ci st8.spill [r14]=r4,SW(R6)-SW(R4) // spill r4 and prefetch offset 0x1c0 2638c2ecf20Sopenharmony_ci lfetch.fault.excl.nt1 [r3],128 // prefetch offset 0x010 2648c2ecf20Sopenharmony_ci ;; 2658c2ecf20Sopenharmony_ci lfetch.fault.excl.nt1 [r3],128 // prefetch offset 0x090 2668c2ecf20Sopenharmony_ci lfetch.fault.excl.nt1 [r2],128 // prefetch offset 0x190 2678c2ecf20Sopenharmony_ci ;; 2688c2ecf20Sopenharmony_ci lfetch.fault.excl.nt1 [r3] // prefetch offset 0x110 2698c2ecf20Sopenharmony_ci lfetch.fault.excl.nt1 [r2] // prefetch offset 0x210 2708c2ecf20Sopenharmony_ci adds r15=SW(R5)+16,sp 2718c2ecf20Sopenharmony_ci#endif 2728c2ecf20Sopenharmony_ci ;; 2738c2ecf20Sopenharmony_ci st8.spill [r15]=r5,SW(R7)-SW(R5) // spill r5 2748c2ecf20Sopenharmony_ci mov.m ar.rsc=0 // put RSE in mode: enforced lazy, little endian, pl 0 2758c2ecf20Sopenharmony_ci add r2=SW(F2)+16,sp // r2 = &sw->f2 2768c2ecf20Sopenharmony_ci ;; 2778c2ecf20Sopenharmony_ci st8.spill [r14]=r6,SW(B0)-SW(R6) // spill r6 2788c2ecf20Sopenharmony_ci mov.m r18=ar.fpsr // preserve fpsr 2798c2ecf20Sopenharmony_ci add r3=SW(F3)+16,sp // r3 = &sw->f3 2808c2ecf20Sopenharmony_ci ;; 2818c2ecf20Sopenharmony_ci stf.spill [r2]=f2,32 2828c2ecf20Sopenharmony_ci mov.m r19=ar.rnat 2838c2ecf20Sopenharmony_ci mov r21=b0 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci stf.spill [r3]=f3,32 2868c2ecf20Sopenharmony_ci st8.spill [r15]=r7,SW(B2)-SW(R7) // spill r7 2878c2ecf20Sopenharmony_ci mov r22=b1 2888c2ecf20Sopenharmony_ci ;; 2898c2ecf20Sopenharmony_ci // since we're done with the spills, read and save ar.unat: 2908c2ecf20Sopenharmony_ci mov.m r29=ar.unat 2918c2ecf20Sopenharmony_ci mov.m r20=ar.bspstore 2928c2ecf20Sopenharmony_ci mov r23=b2 2938c2ecf20Sopenharmony_ci stf.spill [r2]=f4,32 2948c2ecf20Sopenharmony_ci stf.spill [r3]=f5,32 2958c2ecf20Sopenharmony_ci mov r24=b3 2968c2ecf20Sopenharmony_ci ;; 2978c2ecf20Sopenharmony_ci st8 [r14]=r21,SW(B1)-SW(B0) // save b0 2988c2ecf20Sopenharmony_ci st8 [r15]=r23,SW(B3)-SW(B2) // save b2 2998c2ecf20Sopenharmony_ci mov r25=b4 3008c2ecf20Sopenharmony_ci mov r26=b5 3018c2ecf20Sopenharmony_ci ;; 3028c2ecf20Sopenharmony_ci st8 [r14]=r22,SW(B4)-SW(B1) // save b1 3038c2ecf20Sopenharmony_ci st8 [r15]=r24,SW(AR_PFS)-SW(B3) // save b3 3048c2ecf20Sopenharmony_ci mov r21=ar.lc // I-unit 3058c2ecf20Sopenharmony_ci stf.spill [r2]=f12,32 3068c2ecf20Sopenharmony_ci stf.spill [r3]=f13,32 3078c2ecf20Sopenharmony_ci ;; 3088c2ecf20Sopenharmony_ci st8 [r14]=r25,SW(B5)-SW(B4) // save b4 3098c2ecf20Sopenharmony_ci st8 [r15]=r16,SW(AR_LC)-SW(AR_PFS) // save ar.pfs 3108c2ecf20Sopenharmony_ci stf.spill [r2]=f14,32 3118c2ecf20Sopenharmony_ci stf.spill [r3]=f15,32 3128c2ecf20Sopenharmony_ci ;; 3138c2ecf20Sopenharmony_ci st8 [r14]=r26 // save b5 3148c2ecf20Sopenharmony_ci st8 [r15]=r21 // save ar.lc 3158c2ecf20Sopenharmony_ci stf.spill [r2]=f16,32 3168c2ecf20Sopenharmony_ci stf.spill [r3]=f17,32 3178c2ecf20Sopenharmony_ci ;; 3188c2ecf20Sopenharmony_ci stf.spill [r2]=f18,32 3198c2ecf20Sopenharmony_ci stf.spill [r3]=f19,32 3208c2ecf20Sopenharmony_ci ;; 3218c2ecf20Sopenharmony_ci stf.spill [r2]=f20,32 3228c2ecf20Sopenharmony_ci stf.spill [r3]=f21,32 3238c2ecf20Sopenharmony_ci ;; 3248c2ecf20Sopenharmony_ci stf.spill [r2]=f22,32 3258c2ecf20Sopenharmony_ci stf.spill [r3]=f23,32 3268c2ecf20Sopenharmony_ci ;; 3278c2ecf20Sopenharmony_ci stf.spill [r2]=f24,32 3288c2ecf20Sopenharmony_ci stf.spill [r3]=f25,32 3298c2ecf20Sopenharmony_ci ;; 3308c2ecf20Sopenharmony_ci stf.spill [r2]=f26,32 3318c2ecf20Sopenharmony_ci stf.spill [r3]=f27,32 3328c2ecf20Sopenharmony_ci ;; 3338c2ecf20Sopenharmony_ci stf.spill [r2]=f28,32 3348c2ecf20Sopenharmony_ci stf.spill [r3]=f29,32 3358c2ecf20Sopenharmony_ci ;; 3368c2ecf20Sopenharmony_ci stf.spill [r2]=f30,SW(AR_UNAT)-SW(F30) 3378c2ecf20Sopenharmony_ci stf.spill [r3]=f31,SW(PR)-SW(F31) 3388c2ecf20Sopenharmony_ci add r14=SW(CALLER_UNAT)+16,sp 3398c2ecf20Sopenharmony_ci ;; 3408c2ecf20Sopenharmony_ci st8 [r2]=r29,SW(AR_RNAT)-SW(AR_UNAT) // save ar.unat 3418c2ecf20Sopenharmony_ci st8 [r14]=r17,SW(AR_FPSR)-SW(CALLER_UNAT) // save caller_unat 3428c2ecf20Sopenharmony_ci mov r21=pr 3438c2ecf20Sopenharmony_ci ;; 3448c2ecf20Sopenharmony_ci st8 [r2]=r19,SW(AR_BSPSTORE)-SW(AR_RNAT) // save ar.rnat 3458c2ecf20Sopenharmony_ci st8 [r3]=r21 // save predicate registers 3468c2ecf20Sopenharmony_ci ;; 3478c2ecf20Sopenharmony_ci st8 [r2]=r20 // save ar.bspstore 3488c2ecf20Sopenharmony_ci st8 [r14]=r18 // save fpsr 3498c2ecf20Sopenharmony_ci mov ar.rsc=3 // put RSE back into eager mode, pl 0 3508c2ecf20Sopenharmony_ci br.cond.sptk.many b7 3518c2ecf20Sopenharmony_ciEND(save_switch_stack) 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci/* 3548c2ecf20Sopenharmony_ci * load_switch_stack: 3558c2ecf20Sopenharmony_ci * - "invala" MUST be done at call site (normally in DO_LOAD_SWITCH_STACK) 3568c2ecf20Sopenharmony_ci * - b7 holds address to return to 3578c2ecf20Sopenharmony_ci * - must not touch r8-r11 3588c2ecf20Sopenharmony_ci */ 3598c2ecf20Sopenharmony_ciGLOBAL_ENTRY(load_switch_stack) 3608c2ecf20Sopenharmony_ci .prologue 3618c2ecf20Sopenharmony_ci .altrp b7 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci .body 3648c2ecf20Sopenharmony_ci lfetch.fault.nt1 [sp] 3658c2ecf20Sopenharmony_ci adds r2=SW(AR_BSPSTORE)+16,sp 3668c2ecf20Sopenharmony_ci adds r3=SW(AR_UNAT)+16,sp 3678c2ecf20Sopenharmony_ci mov ar.rsc=0 // put RSE into enforced lazy mode 3688c2ecf20Sopenharmony_ci adds r14=SW(CALLER_UNAT)+16,sp 3698c2ecf20Sopenharmony_ci adds r15=SW(AR_FPSR)+16,sp 3708c2ecf20Sopenharmony_ci ;; 3718c2ecf20Sopenharmony_ci ld8 r27=[r2],(SW(B0)-SW(AR_BSPSTORE)) // bspstore 3728c2ecf20Sopenharmony_ci ld8 r29=[r3],(SW(B1)-SW(AR_UNAT)) // unat 3738c2ecf20Sopenharmony_ci ;; 3748c2ecf20Sopenharmony_ci ld8 r21=[r2],16 // restore b0 3758c2ecf20Sopenharmony_ci ld8 r22=[r3],16 // restore b1 3768c2ecf20Sopenharmony_ci ;; 3778c2ecf20Sopenharmony_ci ld8 r23=[r2],16 // restore b2 3788c2ecf20Sopenharmony_ci ld8 r24=[r3],16 // restore b3 3798c2ecf20Sopenharmony_ci ;; 3808c2ecf20Sopenharmony_ci ld8 r25=[r2],16 // restore b4 3818c2ecf20Sopenharmony_ci ld8 r26=[r3],16 // restore b5 3828c2ecf20Sopenharmony_ci ;; 3838c2ecf20Sopenharmony_ci ld8 r16=[r2],(SW(PR)-SW(AR_PFS)) // ar.pfs 3848c2ecf20Sopenharmony_ci ld8 r17=[r3],(SW(AR_RNAT)-SW(AR_LC)) // ar.lc 3858c2ecf20Sopenharmony_ci ;; 3868c2ecf20Sopenharmony_ci ld8 r28=[r2] // restore pr 3878c2ecf20Sopenharmony_ci ld8 r30=[r3] // restore rnat 3888c2ecf20Sopenharmony_ci ;; 3898c2ecf20Sopenharmony_ci ld8 r18=[r14],16 // restore caller's unat 3908c2ecf20Sopenharmony_ci ld8 r19=[r15],24 // restore fpsr 3918c2ecf20Sopenharmony_ci ;; 3928c2ecf20Sopenharmony_ci ldf.fill f2=[r14],32 3938c2ecf20Sopenharmony_ci ldf.fill f3=[r15],32 3948c2ecf20Sopenharmony_ci ;; 3958c2ecf20Sopenharmony_ci ldf.fill f4=[r14],32 3968c2ecf20Sopenharmony_ci ldf.fill f5=[r15],32 3978c2ecf20Sopenharmony_ci ;; 3988c2ecf20Sopenharmony_ci ldf.fill f12=[r14],32 3998c2ecf20Sopenharmony_ci ldf.fill f13=[r15],32 4008c2ecf20Sopenharmony_ci ;; 4018c2ecf20Sopenharmony_ci ldf.fill f14=[r14],32 4028c2ecf20Sopenharmony_ci ldf.fill f15=[r15],32 4038c2ecf20Sopenharmony_ci ;; 4048c2ecf20Sopenharmony_ci ldf.fill f16=[r14],32 4058c2ecf20Sopenharmony_ci ldf.fill f17=[r15],32 4068c2ecf20Sopenharmony_ci ;; 4078c2ecf20Sopenharmony_ci ldf.fill f18=[r14],32 4088c2ecf20Sopenharmony_ci ldf.fill f19=[r15],32 4098c2ecf20Sopenharmony_ci mov b0=r21 4108c2ecf20Sopenharmony_ci ;; 4118c2ecf20Sopenharmony_ci ldf.fill f20=[r14],32 4128c2ecf20Sopenharmony_ci ldf.fill f21=[r15],32 4138c2ecf20Sopenharmony_ci mov b1=r22 4148c2ecf20Sopenharmony_ci ;; 4158c2ecf20Sopenharmony_ci ldf.fill f22=[r14],32 4168c2ecf20Sopenharmony_ci ldf.fill f23=[r15],32 4178c2ecf20Sopenharmony_ci mov b2=r23 4188c2ecf20Sopenharmony_ci ;; 4198c2ecf20Sopenharmony_ci mov ar.bspstore=r27 4208c2ecf20Sopenharmony_ci mov ar.unat=r29 // establish unat holding the NaT bits for r4-r7 4218c2ecf20Sopenharmony_ci mov b3=r24 4228c2ecf20Sopenharmony_ci ;; 4238c2ecf20Sopenharmony_ci ldf.fill f24=[r14],32 4248c2ecf20Sopenharmony_ci ldf.fill f25=[r15],32 4258c2ecf20Sopenharmony_ci mov b4=r25 4268c2ecf20Sopenharmony_ci ;; 4278c2ecf20Sopenharmony_ci ldf.fill f26=[r14],32 4288c2ecf20Sopenharmony_ci ldf.fill f27=[r15],32 4298c2ecf20Sopenharmony_ci mov b5=r26 4308c2ecf20Sopenharmony_ci ;; 4318c2ecf20Sopenharmony_ci ldf.fill f28=[r14],32 4328c2ecf20Sopenharmony_ci ldf.fill f29=[r15],32 4338c2ecf20Sopenharmony_ci mov ar.pfs=r16 4348c2ecf20Sopenharmony_ci ;; 4358c2ecf20Sopenharmony_ci ldf.fill f30=[r14],32 4368c2ecf20Sopenharmony_ci ldf.fill f31=[r15],24 4378c2ecf20Sopenharmony_ci mov ar.lc=r17 4388c2ecf20Sopenharmony_ci ;; 4398c2ecf20Sopenharmony_ci ld8.fill r4=[r14],16 4408c2ecf20Sopenharmony_ci ld8.fill r5=[r15],16 4418c2ecf20Sopenharmony_ci mov pr=r28,-1 4428c2ecf20Sopenharmony_ci ;; 4438c2ecf20Sopenharmony_ci ld8.fill r6=[r14],16 4448c2ecf20Sopenharmony_ci ld8.fill r7=[r15],16 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci mov ar.unat=r18 // restore caller's unat 4478c2ecf20Sopenharmony_ci mov ar.rnat=r30 // must restore after bspstore but before rsc! 4488c2ecf20Sopenharmony_ci mov ar.fpsr=r19 // restore fpsr 4498c2ecf20Sopenharmony_ci mov ar.rsc=3 // put RSE back into eager mode, pl 0 4508c2ecf20Sopenharmony_ci br.cond.sptk.many b7 4518c2ecf20Sopenharmony_ciEND(load_switch_stack) 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci /* 4548c2ecf20Sopenharmony_ci * Invoke a system call, but do some tracing before and after the call. 4558c2ecf20Sopenharmony_ci * We MUST preserve the current register frame throughout this routine 4568c2ecf20Sopenharmony_ci * because some system calls (such as ia64_execve) directly 4578c2ecf20Sopenharmony_ci * manipulate ar.pfs. 4588c2ecf20Sopenharmony_ci */ 4598c2ecf20Sopenharmony_ciGLOBAL_ENTRY(ia64_trace_syscall) 4608c2ecf20Sopenharmony_ci PT_REGS_UNWIND_INFO(0) 4618c2ecf20Sopenharmony_ci /* 4628c2ecf20Sopenharmony_ci * We need to preserve the scratch registers f6-f11 in case the system 4638c2ecf20Sopenharmony_ci * call is sigreturn. 4648c2ecf20Sopenharmony_ci */ 4658c2ecf20Sopenharmony_ci adds r16=PT(F6)+16,sp 4668c2ecf20Sopenharmony_ci adds r17=PT(F7)+16,sp 4678c2ecf20Sopenharmony_ci ;; 4688c2ecf20Sopenharmony_ci stf.spill [r16]=f6,32 4698c2ecf20Sopenharmony_ci stf.spill [r17]=f7,32 4708c2ecf20Sopenharmony_ci ;; 4718c2ecf20Sopenharmony_ci stf.spill [r16]=f8,32 4728c2ecf20Sopenharmony_ci stf.spill [r17]=f9,32 4738c2ecf20Sopenharmony_ci ;; 4748c2ecf20Sopenharmony_ci stf.spill [r16]=f10 4758c2ecf20Sopenharmony_ci stf.spill [r17]=f11 4768c2ecf20Sopenharmony_ci br.call.sptk.many rp=syscall_trace_enter // give parent a chance to catch syscall args 4778c2ecf20Sopenharmony_ci cmp.lt p6,p0=r8,r0 // check tracehook 4788c2ecf20Sopenharmony_ci adds r2=PT(R8)+16,sp // r2 = &pt_regs.r8 4798c2ecf20Sopenharmony_ci adds r3=PT(R10)+16,sp // r3 = &pt_regs.r10 4808c2ecf20Sopenharmony_ci mov r10=0 4818c2ecf20Sopenharmony_ci(p6) br.cond.sptk strace_error // syscall failed -> 4828c2ecf20Sopenharmony_ci adds r16=PT(F6)+16,sp 4838c2ecf20Sopenharmony_ci adds r17=PT(F7)+16,sp 4848c2ecf20Sopenharmony_ci ;; 4858c2ecf20Sopenharmony_ci ldf.fill f6=[r16],32 4868c2ecf20Sopenharmony_ci ldf.fill f7=[r17],32 4878c2ecf20Sopenharmony_ci ;; 4888c2ecf20Sopenharmony_ci ldf.fill f8=[r16],32 4898c2ecf20Sopenharmony_ci ldf.fill f9=[r17],32 4908c2ecf20Sopenharmony_ci ;; 4918c2ecf20Sopenharmony_ci ldf.fill f10=[r16] 4928c2ecf20Sopenharmony_ci ldf.fill f11=[r17] 4938c2ecf20Sopenharmony_ci // the syscall number may have changed, so re-load it and re-calculate the 4948c2ecf20Sopenharmony_ci // syscall entry-point: 4958c2ecf20Sopenharmony_ci adds r15=PT(R15)+16,sp // r15 = &pt_regs.r15 (syscall #) 4968c2ecf20Sopenharmony_ci ;; 4978c2ecf20Sopenharmony_ci ld8 r15=[r15] 4988c2ecf20Sopenharmony_ci mov r3=NR_syscalls - 1 4998c2ecf20Sopenharmony_ci ;; 5008c2ecf20Sopenharmony_ci adds r15=-1024,r15 5018c2ecf20Sopenharmony_ci movl r16=sys_call_table 5028c2ecf20Sopenharmony_ci ;; 5038c2ecf20Sopenharmony_ci shladd r20=r15,3,r16 // r20 = sys_call_table + 8*(syscall-1024) 5048c2ecf20Sopenharmony_ci cmp.leu p6,p7=r15,r3 5058c2ecf20Sopenharmony_ci ;; 5068c2ecf20Sopenharmony_ci(p6) ld8 r20=[r20] // load address of syscall entry point 5078c2ecf20Sopenharmony_ci(p7) movl r20=sys_ni_syscall 5088c2ecf20Sopenharmony_ci ;; 5098c2ecf20Sopenharmony_ci mov b6=r20 5108c2ecf20Sopenharmony_ci br.call.sptk.many rp=b6 // do the syscall 5118c2ecf20Sopenharmony_ci.strace_check_retval: 5128c2ecf20Sopenharmony_ci cmp.lt p6,p0=r8,r0 // syscall failed? 5138c2ecf20Sopenharmony_ci adds r2=PT(R8)+16,sp // r2 = &pt_regs.r8 5148c2ecf20Sopenharmony_ci adds r3=PT(R10)+16,sp // r3 = &pt_regs.r10 5158c2ecf20Sopenharmony_ci mov r10=0 5168c2ecf20Sopenharmony_ci(p6) br.cond.sptk strace_error // syscall failed -> 5178c2ecf20Sopenharmony_ci ;; // avoid RAW on r10 5188c2ecf20Sopenharmony_ci.strace_save_retval: 5198c2ecf20Sopenharmony_ci.mem.offset 0,0; st8.spill [r2]=r8 // store return value in slot for r8 5208c2ecf20Sopenharmony_ci.mem.offset 8,0; st8.spill [r3]=r10 // clear error indication in slot for r10 5218c2ecf20Sopenharmony_ci br.call.sptk.many rp=syscall_trace_leave // give parent a chance to catch return value 5228c2ecf20Sopenharmony_ci.ret3: 5238c2ecf20Sopenharmony_ci(pUStk) cmp.eq.unc p6,p0=r0,r0 // p6 <- pUStk 5248c2ecf20Sopenharmony_ci(pUStk) rsm psr.i // disable interrupts 5258c2ecf20Sopenharmony_ci br.cond.sptk ia64_work_pending_syscall_end 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_cistrace_error: 5288c2ecf20Sopenharmony_ci ld8 r3=[r2] // load pt_regs.r8 5298c2ecf20Sopenharmony_ci sub r9=0,r8 // negate return value to get errno value 5308c2ecf20Sopenharmony_ci ;; 5318c2ecf20Sopenharmony_ci cmp.ne p6,p0=r3,r0 // is pt_regs.r8!=0? 5328c2ecf20Sopenharmony_ci adds r3=16,r2 // r3=&pt_regs.r10 5338c2ecf20Sopenharmony_ci ;; 5348c2ecf20Sopenharmony_ci(p6) mov r10=-1 5358c2ecf20Sopenharmony_ci(p6) mov r8=r9 5368c2ecf20Sopenharmony_ci br.cond.sptk .strace_save_retval 5378c2ecf20Sopenharmony_ciEND(ia64_trace_syscall) 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci /* 5408c2ecf20Sopenharmony_ci * When traced and returning from sigreturn, we invoke syscall_trace but then 5418c2ecf20Sopenharmony_ci * go straight to ia64_leave_kernel rather than ia64_leave_syscall. 5428c2ecf20Sopenharmony_ci */ 5438c2ecf20Sopenharmony_ciGLOBAL_ENTRY(ia64_strace_leave_kernel) 5448c2ecf20Sopenharmony_ci PT_REGS_UNWIND_INFO(0) 5458c2ecf20Sopenharmony_ci{ /* 5468c2ecf20Sopenharmony_ci * Some versions of gas generate bad unwind info if the first instruction of a 5478c2ecf20Sopenharmony_ci * procedure doesn't go into the first slot of a bundle. This is a workaround. 5488c2ecf20Sopenharmony_ci */ 5498c2ecf20Sopenharmony_ci nop.m 0 5508c2ecf20Sopenharmony_ci nop.i 0 5518c2ecf20Sopenharmony_ci br.call.sptk.many rp=syscall_trace_leave // give parent a chance to catch return value 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci.ret4: br.cond.sptk ia64_leave_kernel 5548c2ecf20Sopenharmony_ciEND(ia64_strace_leave_kernel) 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ciENTRY(call_payload) 5578c2ecf20Sopenharmony_ci .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(0) 5588c2ecf20Sopenharmony_ci /* call the kernel_thread payload; fn is in r4, arg - in r5 */ 5598c2ecf20Sopenharmony_ci alloc loc1=ar.pfs,0,3,1,0 5608c2ecf20Sopenharmony_ci mov loc0=rp 5618c2ecf20Sopenharmony_ci mov loc2=gp 5628c2ecf20Sopenharmony_ci mov out0=r5 // arg 5638c2ecf20Sopenharmony_ci ld8 r14 = [r4], 8 // fn.address 5648c2ecf20Sopenharmony_ci ;; 5658c2ecf20Sopenharmony_ci mov b6 = r14 5668c2ecf20Sopenharmony_ci ld8 gp = [r4] // fn.gp 5678c2ecf20Sopenharmony_ci ;; 5688c2ecf20Sopenharmony_ci br.call.sptk.many rp=b6 // fn(arg) 5698c2ecf20Sopenharmony_ci.ret12: mov gp=loc2 5708c2ecf20Sopenharmony_ci mov rp=loc0 5718c2ecf20Sopenharmony_ci mov ar.pfs=loc1 5728c2ecf20Sopenharmony_ci /* ... and if it has returned, we are going to userland */ 5738c2ecf20Sopenharmony_ci cmp.ne pKStk,pUStk=r0,r0 5748c2ecf20Sopenharmony_ci br.ret.sptk.many rp 5758c2ecf20Sopenharmony_ciEND(call_payload) 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ciGLOBAL_ENTRY(ia64_ret_from_clone) 5788c2ecf20Sopenharmony_ci PT_REGS_UNWIND_INFO(0) 5798c2ecf20Sopenharmony_ci{ /* 5808c2ecf20Sopenharmony_ci * Some versions of gas generate bad unwind info if the first instruction of a 5818c2ecf20Sopenharmony_ci * procedure doesn't go into the first slot of a bundle. This is a workaround. 5828c2ecf20Sopenharmony_ci */ 5838c2ecf20Sopenharmony_ci nop.m 0 5848c2ecf20Sopenharmony_ci nop.i 0 5858c2ecf20Sopenharmony_ci /* 5868c2ecf20Sopenharmony_ci * We need to call schedule_tail() to complete the scheduling process. 5878c2ecf20Sopenharmony_ci * Called by ia64_switch_to() after ia64_clone()->copy_thread(). r8 contains the 5888c2ecf20Sopenharmony_ci * address of the previously executing task. 5898c2ecf20Sopenharmony_ci */ 5908c2ecf20Sopenharmony_ci br.call.sptk.many rp=ia64_invoke_schedule_tail 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci.ret8: 5938c2ecf20Sopenharmony_ci(pKStk) br.call.sptk.many rp=call_payload 5948c2ecf20Sopenharmony_ci adds r2=TI_FLAGS+IA64_TASK_SIZE,r13 5958c2ecf20Sopenharmony_ci ;; 5968c2ecf20Sopenharmony_ci ld4 r2=[r2] 5978c2ecf20Sopenharmony_ci ;; 5988c2ecf20Sopenharmony_ci mov r8=0 5998c2ecf20Sopenharmony_ci and r2=_TIF_SYSCALL_TRACEAUDIT,r2 6008c2ecf20Sopenharmony_ci ;; 6018c2ecf20Sopenharmony_ci cmp.ne p6,p0=r2,r0 6028c2ecf20Sopenharmony_ci(p6) br.cond.spnt .strace_check_retval 6038c2ecf20Sopenharmony_ci ;; // added stop bits to prevent r8 dependency 6048c2ecf20Sopenharmony_ciEND(ia64_ret_from_clone) 6058c2ecf20Sopenharmony_ci // fall through 6068c2ecf20Sopenharmony_ciGLOBAL_ENTRY(ia64_ret_from_syscall) 6078c2ecf20Sopenharmony_ci PT_REGS_UNWIND_INFO(0) 6088c2ecf20Sopenharmony_ci cmp.ge p6,p7=r8,r0 // syscall executed successfully? 6098c2ecf20Sopenharmony_ci adds r2=PT(R8)+16,sp // r2 = &pt_regs.r8 6108c2ecf20Sopenharmony_ci mov r10=r0 // clear error indication in r10 6118c2ecf20Sopenharmony_ci(p7) br.cond.spnt handle_syscall_error // handle potential syscall failure 6128c2ecf20Sopenharmony_ciEND(ia64_ret_from_syscall) 6138c2ecf20Sopenharmony_ci // fall through 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci/* 6168c2ecf20Sopenharmony_ci * ia64_leave_syscall(): Same as ia64_leave_kernel, except that it doesn't 6178c2ecf20Sopenharmony_ci * need to switch to bank 0 and doesn't restore the scratch registers. 6188c2ecf20Sopenharmony_ci * To avoid leaking kernel bits, the scratch registers are set to 6198c2ecf20Sopenharmony_ci * the following known-to-be-safe values: 6208c2ecf20Sopenharmony_ci * 6218c2ecf20Sopenharmony_ci * r1: restored (global pointer) 6228c2ecf20Sopenharmony_ci * r2: cleared 6238c2ecf20Sopenharmony_ci * r3: 1 (when returning to user-level) 6248c2ecf20Sopenharmony_ci * r8-r11: restored (syscall return value(s)) 6258c2ecf20Sopenharmony_ci * r12: restored (user-level stack pointer) 6268c2ecf20Sopenharmony_ci * r13: restored (user-level thread pointer) 6278c2ecf20Sopenharmony_ci * r14: set to __kernel_syscall_via_epc 6288c2ecf20Sopenharmony_ci * r15: restored (syscall #) 6298c2ecf20Sopenharmony_ci * r16-r17: cleared 6308c2ecf20Sopenharmony_ci * r18: user-level b6 6318c2ecf20Sopenharmony_ci * r19: cleared 6328c2ecf20Sopenharmony_ci * r20: user-level ar.fpsr 6338c2ecf20Sopenharmony_ci * r21: user-level b0 6348c2ecf20Sopenharmony_ci * r22: cleared 6358c2ecf20Sopenharmony_ci * r23: user-level ar.bspstore 6368c2ecf20Sopenharmony_ci * r24: user-level ar.rnat 6378c2ecf20Sopenharmony_ci * r25: user-level ar.unat 6388c2ecf20Sopenharmony_ci * r26: user-level ar.pfs 6398c2ecf20Sopenharmony_ci * r27: user-level ar.rsc 6408c2ecf20Sopenharmony_ci * r28: user-level ip 6418c2ecf20Sopenharmony_ci * r29: user-level psr 6428c2ecf20Sopenharmony_ci * r30: user-level cfm 6438c2ecf20Sopenharmony_ci * r31: user-level pr 6448c2ecf20Sopenharmony_ci * f6-f11: cleared 6458c2ecf20Sopenharmony_ci * pr: restored (user-level pr) 6468c2ecf20Sopenharmony_ci * b0: restored (user-level rp) 6478c2ecf20Sopenharmony_ci * b6: restored 6488c2ecf20Sopenharmony_ci * b7: set to __kernel_syscall_via_epc 6498c2ecf20Sopenharmony_ci * ar.unat: restored (user-level ar.unat) 6508c2ecf20Sopenharmony_ci * ar.pfs: restored (user-level ar.pfs) 6518c2ecf20Sopenharmony_ci * ar.rsc: restored (user-level ar.rsc) 6528c2ecf20Sopenharmony_ci * ar.rnat: restored (user-level ar.rnat) 6538c2ecf20Sopenharmony_ci * ar.bspstore: restored (user-level ar.bspstore) 6548c2ecf20Sopenharmony_ci * ar.fpsr: restored (user-level ar.fpsr) 6558c2ecf20Sopenharmony_ci * ar.ccv: cleared 6568c2ecf20Sopenharmony_ci * ar.csd: cleared 6578c2ecf20Sopenharmony_ci * ar.ssd: cleared 6588c2ecf20Sopenharmony_ci */ 6598c2ecf20Sopenharmony_ciGLOBAL_ENTRY(ia64_leave_syscall) 6608c2ecf20Sopenharmony_ci PT_REGS_UNWIND_INFO(0) 6618c2ecf20Sopenharmony_ci /* 6628c2ecf20Sopenharmony_ci * work.need_resched etc. mustn't get changed by this CPU before it returns to 6638c2ecf20Sopenharmony_ci * user- or fsys-mode, hence we disable interrupts early on. 6648c2ecf20Sopenharmony_ci * 6658c2ecf20Sopenharmony_ci * p6 controls whether current_thread_info()->flags needs to be check for 6668c2ecf20Sopenharmony_ci * extra work. We always check for extra work when returning to user-level. 6678c2ecf20Sopenharmony_ci * With CONFIG_PREEMPTION, we also check for extra work when the preempt_count 6688c2ecf20Sopenharmony_ci * is 0. After extra work processing has been completed, execution 6698c2ecf20Sopenharmony_ci * resumes at ia64_work_processed_syscall with p6 set to 1 if the extra-work-check 6708c2ecf20Sopenharmony_ci * needs to be redone. 6718c2ecf20Sopenharmony_ci */ 6728c2ecf20Sopenharmony_ci#ifdef CONFIG_PREEMPTION 6738c2ecf20Sopenharmony_ci RSM_PSR_I(p0, r2, r18) // disable interrupts 6748c2ecf20Sopenharmony_ci cmp.eq pLvSys,p0=r0,r0 // pLvSys=1: leave from syscall 6758c2ecf20Sopenharmony_ci(pKStk) adds r20=TI_PRE_COUNT+IA64_TASK_SIZE,r13 6768c2ecf20Sopenharmony_ci ;; 6778c2ecf20Sopenharmony_ci .pred.rel.mutex pUStk,pKStk 6788c2ecf20Sopenharmony_ci(pKStk) ld4 r21=[r20] // r21 <- preempt_count 6798c2ecf20Sopenharmony_ci(pUStk) mov r21=0 // r21 <- 0 6808c2ecf20Sopenharmony_ci ;; 6818c2ecf20Sopenharmony_ci cmp.eq p6,p0=r21,r0 // p6 <- pUStk || (preempt_count == 0) 6828c2ecf20Sopenharmony_ci#else /* !CONFIG_PREEMPTION */ 6838c2ecf20Sopenharmony_ci RSM_PSR_I(pUStk, r2, r18) 6848c2ecf20Sopenharmony_ci cmp.eq pLvSys,p0=r0,r0 // pLvSys=1: leave from syscall 6858c2ecf20Sopenharmony_ci(pUStk) cmp.eq.unc p6,p0=r0,r0 // p6 <- pUStk 6868c2ecf20Sopenharmony_ci#endif 6878c2ecf20Sopenharmony_ci.global ia64_work_processed_syscall; 6888c2ecf20Sopenharmony_ciia64_work_processed_syscall: 6898c2ecf20Sopenharmony_ci#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE 6908c2ecf20Sopenharmony_ci adds r2=PT(LOADRS)+16,r12 6918c2ecf20Sopenharmony_ci MOV_FROM_ITC(pUStk, p9, r22, r19) // fetch time at leave 6928c2ecf20Sopenharmony_ci adds r18=TI_FLAGS+IA64_TASK_SIZE,r13 6938c2ecf20Sopenharmony_ci ;; 6948c2ecf20Sopenharmony_ci(p6) ld4 r31=[r18] // load current_thread_info()->flags 6958c2ecf20Sopenharmony_ci ld8 r19=[r2],PT(B6)-PT(LOADRS) // load ar.rsc value for "loadrs" 6968c2ecf20Sopenharmony_ci adds r3=PT(AR_BSPSTORE)+16,r12 // deferred 6978c2ecf20Sopenharmony_ci ;; 6988c2ecf20Sopenharmony_ci#else 6998c2ecf20Sopenharmony_ci adds r2=PT(LOADRS)+16,r12 7008c2ecf20Sopenharmony_ci adds r3=PT(AR_BSPSTORE)+16,r12 7018c2ecf20Sopenharmony_ci adds r18=TI_FLAGS+IA64_TASK_SIZE,r13 7028c2ecf20Sopenharmony_ci ;; 7038c2ecf20Sopenharmony_ci(p6) ld4 r31=[r18] // load current_thread_info()->flags 7048c2ecf20Sopenharmony_ci ld8 r19=[r2],PT(B6)-PT(LOADRS) // load ar.rsc value for "loadrs" 7058c2ecf20Sopenharmony_ci nop.i 0 7068c2ecf20Sopenharmony_ci ;; 7078c2ecf20Sopenharmony_ci#endif 7088c2ecf20Sopenharmony_ci mov r16=ar.bsp // M2 get existing backing store pointer 7098c2ecf20Sopenharmony_ci ld8 r18=[r2],PT(R9)-PT(B6) // load b6 7108c2ecf20Sopenharmony_ci(p6) and r15=TIF_WORK_MASK,r31 // any work other than TIF_SYSCALL_TRACE? 7118c2ecf20Sopenharmony_ci ;; 7128c2ecf20Sopenharmony_ci ld8 r23=[r3],PT(R11)-PT(AR_BSPSTORE) // load ar.bspstore (may be garbage) 7138c2ecf20Sopenharmony_ci(p6) cmp4.ne.unc p6,p0=r15, r0 // any special work pending? 7148c2ecf20Sopenharmony_ci(p6) br.cond.spnt .work_pending_syscall 7158c2ecf20Sopenharmony_ci ;; 7168c2ecf20Sopenharmony_ci // start restoring the state saved on the kernel stack (struct pt_regs): 7178c2ecf20Sopenharmony_ci ld8 r9=[r2],PT(CR_IPSR)-PT(R9) 7188c2ecf20Sopenharmony_ci ld8 r11=[r3],PT(CR_IIP)-PT(R11) 7198c2ecf20Sopenharmony_ci(pNonSys) break 0 // bug check: we shouldn't be here if pNonSys is TRUE! 7208c2ecf20Sopenharmony_ci ;; 7218c2ecf20Sopenharmony_ci invala // M0|1 invalidate ALAT 7228c2ecf20Sopenharmony_ci RSM_PSR_I_IC(r28, r29, r30) // M2 turn off interrupts and interruption collection 7238c2ecf20Sopenharmony_ci cmp.eq p9,p0=r0,r0 // A set p9 to indicate that we should restore cr.ifs 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci ld8 r29=[r2],16 // M0|1 load cr.ipsr 7268c2ecf20Sopenharmony_ci ld8 r28=[r3],16 // M0|1 load cr.iip 7278c2ecf20Sopenharmony_ci#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE 7288c2ecf20Sopenharmony_ci(pUStk) add r14=TI_AC_LEAVE+IA64_TASK_SIZE,r13 7298c2ecf20Sopenharmony_ci ;; 7308c2ecf20Sopenharmony_ci ld8 r30=[r2],16 // M0|1 load cr.ifs 7318c2ecf20Sopenharmony_ci ld8 r25=[r3],16 // M0|1 load ar.unat 7328c2ecf20Sopenharmony_ci(pUStk) add r15=IA64_TASK_THREAD_ON_USTACK_OFFSET,r13 7338c2ecf20Sopenharmony_ci ;; 7348c2ecf20Sopenharmony_ci#else 7358c2ecf20Sopenharmony_ci mov r22=r0 // A clear r22 7368c2ecf20Sopenharmony_ci ;; 7378c2ecf20Sopenharmony_ci ld8 r30=[r2],16 // M0|1 load cr.ifs 7388c2ecf20Sopenharmony_ci ld8 r25=[r3],16 // M0|1 load ar.unat 7398c2ecf20Sopenharmony_ci(pUStk) add r14=IA64_TASK_THREAD_ON_USTACK_OFFSET,r13 7408c2ecf20Sopenharmony_ci ;; 7418c2ecf20Sopenharmony_ci#endif 7428c2ecf20Sopenharmony_ci ld8 r26=[r2],PT(B0)-PT(AR_PFS) // M0|1 load ar.pfs 7438c2ecf20Sopenharmony_ci MOV_FROM_PSR(pKStk, r22, r21) // M2 read PSR now that interrupts are disabled 7448c2ecf20Sopenharmony_ci nop 0 7458c2ecf20Sopenharmony_ci ;; 7468c2ecf20Sopenharmony_ci ld8 r21=[r2],PT(AR_RNAT)-PT(B0) // M0|1 load b0 7478c2ecf20Sopenharmony_ci ld8 r27=[r3],PT(PR)-PT(AR_RSC) // M0|1 load ar.rsc 7488c2ecf20Sopenharmony_ci mov f6=f0 // F clear f6 7498c2ecf20Sopenharmony_ci ;; 7508c2ecf20Sopenharmony_ci ld8 r24=[r2],PT(AR_FPSR)-PT(AR_RNAT) // M0|1 load ar.rnat (may be garbage) 7518c2ecf20Sopenharmony_ci ld8 r31=[r3],PT(R1)-PT(PR) // M0|1 load predicates 7528c2ecf20Sopenharmony_ci mov f7=f0 // F clear f7 7538c2ecf20Sopenharmony_ci ;; 7548c2ecf20Sopenharmony_ci ld8 r20=[r2],PT(R12)-PT(AR_FPSR) // M0|1 load ar.fpsr 7558c2ecf20Sopenharmony_ci ld8.fill r1=[r3],16 // M0|1 load r1 7568c2ecf20Sopenharmony_ci(pUStk) mov r17=1 // A 7578c2ecf20Sopenharmony_ci ;; 7588c2ecf20Sopenharmony_ci#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE 7598c2ecf20Sopenharmony_ci(pUStk) st1 [r15]=r17 // M2|3 7608c2ecf20Sopenharmony_ci#else 7618c2ecf20Sopenharmony_ci(pUStk) st1 [r14]=r17 // M2|3 7628c2ecf20Sopenharmony_ci#endif 7638c2ecf20Sopenharmony_ci ld8.fill r13=[r3],16 // M0|1 7648c2ecf20Sopenharmony_ci mov f8=f0 // F clear f8 7658c2ecf20Sopenharmony_ci ;; 7668c2ecf20Sopenharmony_ci ld8.fill r12=[r2] // M0|1 restore r12 (sp) 7678c2ecf20Sopenharmony_ci ld8.fill r15=[r3] // M0|1 restore r15 7688c2ecf20Sopenharmony_ci mov b6=r18 // I0 restore b6 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci LOAD_PHYS_STACK_REG_SIZE(r17) 7718c2ecf20Sopenharmony_ci mov f9=f0 // F clear f9 7728c2ecf20Sopenharmony_ci(pKStk) br.cond.dpnt.many skip_rbs_switch // B 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci srlz.d // M0 ensure interruption collection is off (for cover) 7758c2ecf20Sopenharmony_ci shr.u r18=r19,16 // I0|1 get byte size of existing "dirty" partition 7768c2ecf20Sopenharmony_ci COVER // B add current frame into dirty partition & set cr.ifs 7778c2ecf20Sopenharmony_ci ;; 7788c2ecf20Sopenharmony_ci#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE 7798c2ecf20Sopenharmony_ci mov r19=ar.bsp // M2 get new backing store pointer 7808c2ecf20Sopenharmony_ci st8 [r14]=r22 // M save time at leave 7818c2ecf20Sopenharmony_ci mov f10=f0 // F clear f10 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci mov r22=r0 // A clear r22 7848c2ecf20Sopenharmony_ci movl r14=__kernel_syscall_via_epc // X 7858c2ecf20Sopenharmony_ci ;; 7868c2ecf20Sopenharmony_ci#else 7878c2ecf20Sopenharmony_ci mov r19=ar.bsp // M2 get new backing store pointer 7888c2ecf20Sopenharmony_ci mov f10=f0 // F clear f10 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci nop.m 0 7918c2ecf20Sopenharmony_ci movl r14=__kernel_syscall_via_epc // X 7928c2ecf20Sopenharmony_ci ;; 7938c2ecf20Sopenharmony_ci#endif 7948c2ecf20Sopenharmony_ci mov.m ar.csd=r0 // M2 clear ar.csd 7958c2ecf20Sopenharmony_ci mov.m ar.ccv=r0 // M2 clear ar.ccv 7968c2ecf20Sopenharmony_ci mov b7=r14 // I0 clear b7 (hint with __kernel_syscall_via_epc) 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci mov.m ar.ssd=r0 // M2 clear ar.ssd 7998c2ecf20Sopenharmony_ci mov f11=f0 // F clear f11 8008c2ecf20Sopenharmony_ci br.cond.sptk.many rbs_switch // B 8018c2ecf20Sopenharmony_ciEND(ia64_leave_syscall) 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ciGLOBAL_ENTRY(ia64_leave_kernel) 8048c2ecf20Sopenharmony_ci PT_REGS_UNWIND_INFO(0) 8058c2ecf20Sopenharmony_ci /* 8068c2ecf20Sopenharmony_ci * work.need_resched etc. mustn't get changed by this CPU before it returns to 8078c2ecf20Sopenharmony_ci * user- or fsys-mode, hence we disable interrupts early on. 8088c2ecf20Sopenharmony_ci * 8098c2ecf20Sopenharmony_ci * p6 controls whether current_thread_info()->flags needs to be check for 8108c2ecf20Sopenharmony_ci * extra work. We always check for extra work when returning to user-level. 8118c2ecf20Sopenharmony_ci * With CONFIG_PREEMPTION, we also check for extra work when the preempt_count 8128c2ecf20Sopenharmony_ci * is 0. After extra work processing has been completed, execution 8138c2ecf20Sopenharmony_ci * resumes at .work_processed_syscall with p6 set to 1 if the extra-work-check 8148c2ecf20Sopenharmony_ci * needs to be redone. 8158c2ecf20Sopenharmony_ci */ 8168c2ecf20Sopenharmony_ci#ifdef CONFIG_PREEMPTION 8178c2ecf20Sopenharmony_ci RSM_PSR_I(p0, r17, r31) // disable interrupts 8188c2ecf20Sopenharmony_ci cmp.eq p0,pLvSys=r0,r0 // pLvSys=0: leave from kernel 8198c2ecf20Sopenharmony_ci(pKStk) adds r20=TI_PRE_COUNT+IA64_TASK_SIZE,r13 8208c2ecf20Sopenharmony_ci ;; 8218c2ecf20Sopenharmony_ci .pred.rel.mutex pUStk,pKStk 8228c2ecf20Sopenharmony_ci(pKStk) ld4 r21=[r20] // r21 <- preempt_count 8238c2ecf20Sopenharmony_ci(pUStk) mov r21=0 // r21 <- 0 8248c2ecf20Sopenharmony_ci ;; 8258c2ecf20Sopenharmony_ci cmp.eq p6,p0=r21,r0 // p6 <- pUStk || (preempt_count == 0) 8268c2ecf20Sopenharmony_ci#else 8278c2ecf20Sopenharmony_ci RSM_PSR_I(pUStk, r17, r31) 8288c2ecf20Sopenharmony_ci cmp.eq p0,pLvSys=r0,r0 // pLvSys=0: leave from kernel 8298c2ecf20Sopenharmony_ci(pUStk) cmp.eq.unc p6,p0=r0,r0 // p6 <- pUStk 8308c2ecf20Sopenharmony_ci#endif 8318c2ecf20Sopenharmony_ci.work_processed_kernel: 8328c2ecf20Sopenharmony_ci adds r17=TI_FLAGS+IA64_TASK_SIZE,r13 8338c2ecf20Sopenharmony_ci ;; 8348c2ecf20Sopenharmony_ci(p6) ld4 r31=[r17] // load current_thread_info()->flags 8358c2ecf20Sopenharmony_ci adds r21=PT(PR)+16,r12 8368c2ecf20Sopenharmony_ci ;; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci lfetch [r21],PT(CR_IPSR)-PT(PR) 8398c2ecf20Sopenharmony_ci adds r2=PT(B6)+16,r12 8408c2ecf20Sopenharmony_ci adds r3=PT(R16)+16,r12 8418c2ecf20Sopenharmony_ci ;; 8428c2ecf20Sopenharmony_ci lfetch [r21] 8438c2ecf20Sopenharmony_ci ld8 r28=[r2],8 // load b6 8448c2ecf20Sopenharmony_ci adds r29=PT(R24)+16,r12 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci ld8.fill r16=[r3],PT(AR_CSD)-PT(R16) 8478c2ecf20Sopenharmony_ci adds r30=PT(AR_CCV)+16,r12 8488c2ecf20Sopenharmony_ci(p6) and r19=TIF_WORK_MASK,r31 // any work other than TIF_SYSCALL_TRACE? 8498c2ecf20Sopenharmony_ci ;; 8508c2ecf20Sopenharmony_ci ld8.fill r24=[r29] 8518c2ecf20Sopenharmony_ci ld8 r15=[r30] // load ar.ccv 8528c2ecf20Sopenharmony_ci(p6) cmp4.ne.unc p6,p0=r19, r0 // any special work pending? 8538c2ecf20Sopenharmony_ci ;; 8548c2ecf20Sopenharmony_ci ld8 r29=[r2],16 // load b7 8558c2ecf20Sopenharmony_ci ld8 r30=[r3],16 // load ar.csd 8568c2ecf20Sopenharmony_ci(p6) br.cond.spnt .work_pending 8578c2ecf20Sopenharmony_ci ;; 8588c2ecf20Sopenharmony_ci ld8 r31=[r2],16 // load ar.ssd 8598c2ecf20Sopenharmony_ci ld8.fill r8=[r3],16 8608c2ecf20Sopenharmony_ci ;; 8618c2ecf20Sopenharmony_ci ld8.fill r9=[r2],16 8628c2ecf20Sopenharmony_ci ld8.fill r10=[r3],PT(R17)-PT(R10) 8638c2ecf20Sopenharmony_ci ;; 8648c2ecf20Sopenharmony_ci ld8.fill r11=[r2],PT(R18)-PT(R11) 8658c2ecf20Sopenharmony_ci ld8.fill r17=[r3],16 8668c2ecf20Sopenharmony_ci ;; 8678c2ecf20Sopenharmony_ci ld8.fill r18=[r2],16 8688c2ecf20Sopenharmony_ci ld8.fill r19=[r3],16 8698c2ecf20Sopenharmony_ci ;; 8708c2ecf20Sopenharmony_ci ld8.fill r20=[r2],16 8718c2ecf20Sopenharmony_ci ld8.fill r21=[r3],16 8728c2ecf20Sopenharmony_ci mov ar.csd=r30 8738c2ecf20Sopenharmony_ci mov ar.ssd=r31 8748c2ecf20Sopenharmony_ci ;; 8758c2ecf20Sopenharmony_ci RSM_PSR_I_IC(r23, r22, r25) // initiate turning off of interrupt and interruption collection 8768c2ecf20Sopenharmony_ci invala // invalidate ALAT 8778c2ecf20Sopenharmony_ci ;; 8788c2ecf20Sopenharmony_ci ld8.fill r22=[r2],24 8798c2ecf20Sopenharmony_ci ld8.fill r23=[r3],24 8808c2ecf20Sopenharmony_ci mov b6=r28 8818c2ecf20Sopenharmony_ci ;; 8828c2ecf20Sopenharmony_ci ld8.fill r25=[r2],16 8838c2ecf20Sopenharmony_ci ld8.fill r26=[r3],16 8848c2ecf20Sopenharmony_ci mov b7=r29 8858c2ecf20Sopenharmony_ci ;; 8868c2ecf20Sopenharmony_ci ld8.fill r27=[r2],16 8878c2ecf20Sopenharmony_ci ld8.fill r28=[r3],16 8888c2ecf20Sopenharmony_ci ;; 8898c2ecf20Sopenharmony_ci ld8.fill r29=[r2],16 8908c2ecf20Sopenharmony_ci ld8.fill r30=[r3],24 8918c2ecf20Sopenharmony_ci ;; 8928c2ecf20Sopenharmony_ci ld8.fill r31=[r2],PT(F9)-PT(R31) 8938c2ecf20Sopenharmony_ci adds r3=PT(F10)-PT(F6),r3 8948c2ecf20Sopenharmony_ci ;; 8958c2ecf20Sopenharmony_ci ldf.fill f9=[r2],PT(F6)-PT(F9) 8968c2ecf20Sopenharmony_ci ldf.fill f10=[r3],PT(F8)-PT(F10) 8978c2ecf20Sopenharmony_ci ;; 8988c2ecf20Sopenharmony_ci ldf.fill f6=[r2],PT(F7)-PT(F6) 8998c2ecf20Sopenharmony_ci ;; 9008c2ecf20Sopenharmony_ci ldf.fill f7=[r2],PT(F11)-PT(F7) 9018c2ecf20Sopenharmony_ci ldf.fill f8=[r3],32 9028c2ecf20Sopenharmony_ci ;; 9038c2ecf20Sopenharmony_ci srlz.d // ensure that inter. collection is off (VHPT is don't care, since text is pinned) 9048c2ecf20Sopenharmony_ci mov ar.ccv=r15 9058c2ecf20Sopenharmony_ci ;; 9068c2ecf20Sopenharmony_ci ldf.fill f11=[r2] 9078c2ecf20Sopenharmony_ci BSW_0(r2, r3, r15) // switch back to bank 0 (no stop bit required beforehand...) 9088c2ecf20Sopenharmony_ci ;; 9098c2ecf20Sopenharmony_ci(pUStk) mov r18=IA64_KR(CURRENT)// M2 (12 cycle read latency) 9108c2ecf20Sopenharmony_ci adds r16=PT(CR_IPSR)+16,r12 9118c2ecf20Sopenharmony_ci adds r17=PT(CR_IIP)+16,r12 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE 9148c2ecf20Sopenharmony_ci .pred.rel.mutex pUStk,pKStk 9158c2ecf20Sopenharmony_ci MOV_FROM_PSR(pKStk, r22, r29) // M2 read PSR now that interrupts are disabled 9168c2ecf20Sopenharmony_ci MOV_FROM_ITC(pUStk, p9, r22, r29) // M fetch time at leave 9178c2ecf20Sopenharmony_ci nop.i 0 9188c2ecf20Sopenharmony_ci ;; 9198c2ecf20Sopenharmony_ci#else 9208c2ecf20Sopenharmony_ci MOV_FROM_PSR(pKStk, r22, r29) // M2 read PSR now that interrupts are disabled 9218c2ecf20Sopenharmony_ci nop.i 0 9228c2ecf20Sopenharmony_ci nop.i 0 9238c2ecf20Sopenharmony_ci ;; 9248c2ecf20Sopenharmony_ci#endif 9258c2ecf20Sopenharmony_ci ld8 r29=[r16],16 // load cr.ipsr 9268c2ecf20Sopenharmony_ci ld8 r28=[r17],16 // load cr.iip 9278c2ecf20Sopenharmony_ci ;; 9288c2ecf20Sopenharmony_ci ld8 r30=[r16],16 // load cr.ifs 9298c2ecf20Sopenharmony_ci ld8 r25=[r17],16 // load ar.unat 9308c2ecf20Sopenharmony_ci ;; 9318c2ecf20Sopenharmony_ci ld8 r26=[r16],16 // load ar.pfs 9328c2ecf20Sopenharmony_ci ld8 r27=[r17],16 // load ar.rsc 9338c2ecf20Sopenharmony_ci cmp.eq p9,p0=r0,r0 // set p9 to indicate that we should restore cr.ifs 9348c2ecf20Sopenharmony_ci ;; 9358c2ecf20Sopenharmony_ci ld8 r24=[r16],16 // load ar.rnat (may be garbage) 9368c2ecf20Sopenharmony_ci ld8 r23=[r17],16 // load ar.bspstore (may be garbage) 9378c2ecf20Sopenharmony_ci ;; 9388c2ecf20Sopenharmony_ci ld8 r31=[r16],16 // load predicates 9398c2ecf20Sopenharmony_ci ld8 r21=[r17],16 // load b0 9408c2ecf20Sopenharmony_ci ;; 9418c2ecf20Sopenharmony_ci ld8 r19=[r16],16 // load ar.rsc value for "loadrs" 9428c2ecf20Sopenharmony_ci ld8.fill r1=[r17],16 // load r1 9438c2ecf20Sopenharmony_ci ;; 9448c2ecf20Sopenharmony_ci ld8.fill r12=[r16],16 9458c2ecf20Sopenharmony_ci ld8.fill r13=[r17],16 9468c2ecf20Sopenharmony_ci#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE 9478c2ecf20Sopenharmony_ci(pUStk) adds r3=TI_AC_LEAVE+IA64_TASK_SIZE,r18 9488c2ecf20Sopenharmony_ci#else 9498c2ecf20Sopenharmony_ci(pUStk) adds r18=IA64_TASK_THREAD_ON_USTACK_OFFSET,r18 9508c2ecf20Sopenharmony_ci#endif 9518c2ecf20Sopenharmony_ci ;; 9528c2ecf20Sopenharmony_ci ld8 r20=[r16],16 // ar.fpsr 9538c2ecf20Sopenharmony_ci ld8.fill r15=[r17],16 9548c2ecf20Sopenharmony_ci#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE 9558c2ecf20Sopenharmony_ci(pUStk) adds r18=IA64_TASK_THREAD_ON_USTACK_OFFSET,r18 // deferred 9568c2ecf20Sopenharmony_ci#endif 9578c2ecf20Sopenharmony_ci ;; 9588c2ecf20Sopenharmony_ci ld8.fill r14=[r16],16 9598c2ecf20Sopenharmony_ci ld8.fill r2=[r17] 9608c2ecf20Sopenharmony_ci(pUStk) mov r17=1 9618c2ecf20Sopenharmony_ci ;; 9628c2ecf20Sopenharmony_ci#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE 9638c2ecf20Sopenharmony_ci // mmi_ : ld8 st1 shr;; mmi_ : st8 st1 shr;; 9648c2ecf20Sopenharmony_ci // mib : mov add br -> mib : ld8 add br 9658c2ecf20Sopenharmony_ci // bbb_ : br nop cover;; mbb_ : mov br cover;; 9668c2ecf20Sopenharmony_ci // 9678c2ecf20Sopenharmony_ci // no one require bsp in r16 if (pKStk) branch is selected. 9688c2ecf20Sopenharmony_ci(pUStk) st8 [r3]=r22 // save time at leave 9698c2ecf20Sopenharmony_ci(pUStk) st1 [r18]=r17 // restore current->thread.on_ustack 9708c2ecf20Sopenharmony_ci shr.u r18=r19,16 // get byte size of existing "dirty" partition 9718c2ecf20Sopenharmony_ci ;; 9728c2ecf20Sopenharmony_ci ld8.fill r3=[r16] // deferred 9738c2ecf20Sopenharmony_ci LOAD_PHYS_STACK_REG_SIZE(r17) 9748c2ecf20Sopenharmony_ci(pKStk) br.cond.dpnt skip_rbs_switch 9758c2ecf20Sopenharmony_ci mov r16=ar.bsp // get existing backing store pointer 9768c2ecf20Sopenharmony_ci#else 9778c2ecf20Sopenharmony_ci ld8.fill r3=[r16] 9788c2ecf20Sopenharmony_ci(pUStk) st1 [r18]=r17 // restore current->thread.on_ustack 9798c2ecf20Sopenharmony_ci shr.u r18=r19,16 // get byte size of existing "dirty" partition 9808c2ecf20Sopenharmony_ci ;; 9818c2ecf20Sopenharmony_ci mov r16=ar.bsp // get existing backing store pointer 9828c2ecf20Sopenharmony_ci LOAD_PHYS_STACK_REG_SIZE(r17) 9838c2ecf20Sopenharmony_ci(pKStk) br.cond.dpnt skip_rbs_switch 9848c2ecf20Sopenharmony_ci#endif 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci /* 9878c2ecf20Sopenharmony_ci * Restore user backing store. 9888c2ecf20Sopenharmony_ci * 9898c2ecf20Sopenharmony_ci * NOTE: alloc, loadrs, and cover can't be predicated. 9908c2ecf20Sopenharmony_ci */ 9918c2ecf20Sopenharmony_ci(pNonSys) br.cond.dpnt dont_preserve_current_frame 9928c2ecf20Sopenharmony_ci COVER // add current frame into dirty partition and set cr.ifs 9938c2ecf20Sopenharmony_ci ;; 9948c2ecf20Sopenharmony_ci mov r19=ar.bsp // get new backing store pointer 9958c2ecf20Sopenharmony_cirbs_switch: 9968c2ecf20Sopenharmony_ci sub r16=r16,r18 // krbs = old bsp - size of dirty partition 9978c2ecf20Sopenharmony_ci cmp.ne p9,p0=r0,r0 // clear p9 to skip restore of cr.ifs 9988c2ecf20Sopenharmony_ci ;; 9998c2ecf20Sopenharmony_ci sub r19=r19,r16 // calculate total byte size of dirty partition 10008c2ecf20Sopenharmony_ci add r18=64,r18 // don't force in0-in7 into memory... 10018c2ecf20Sopenharmony_ci ;; 10028c2ecf20Sopenharmony_ci shl r19=r19,16 // shift size of dirty partition into loadrs position 10038c2ecf20Sopenharmony_ci ;; 10048c2ecf20Sopenharmony_cidont_preserve_current_frame: 10058c2ecf20Sopenharmony_ci /* 10068c2ecf20Sopenharmony_ci * To prevent leaking bits between the kernel and user-space, 10078c2ecf20Sopenharmony_ci * we must clear the stacked registers in the "invalid" partition here. 10088c2ecf20Sopenharmony_ci * Not pretty, but at least it's fast (3.34 registers/cycle on Itanium, 10098c2ecf20Sopenharmony_ci * 5 registers/cycle on McKinley). 10108c2ecf20Sopenharmony_ci */ 10118c2ecf20Sopenharmony_ci# define pRecurse p6 10128c2ecf20Sopenharmony_ci# define pReturn p7 10138c2ecf20Sopenharmony_ci#ifdef CONFIG_ITANIUM 10148c2ecf20Sopenharmony_ci# define Nregs 10 10158c2ecf20Sopenharmony_ci#else 10168c2ecf20Sopenharmony_ci# define Nregs 14 10178c2ecf20Sopenharmony_ci#endif 10188c2ecf20Sopenharmony_ci alloc loc0=ar.pfs,2,Nregs-2,2,0 10198c2ecf20Sopenharmony_ci shr.u loc1=r18,9 // RNaTslots <= floor(dirtySize / (64*8)) 10208c2ecf20Sopenharmony_ci sub r17=r17,r18 // r17 = (physStackedSize + 8) - dirtySize 10218c2ecf20Sopenharmony_ci ;; 10228c2ecf20Sopenharmony_ci mov ar.rsc=r19 // load ar.rsc to be used for "loadrs" 10238c2ecf20Sopenharmony_ci shladd in0=loc1,3,r17 10248c2ecf20Sopenharmony_ci mov in1=0 10258c2ecf20Sopenharmony_ci ;; 10268c2ecf20Sopenharmony_ci TEXT_ALIGN(32) 10278c2ecf20Sopenharmony_cirse_clear_invalid: 10288c2ecf20Sopenharmony_ci#ifdef CONFIG_ITANIUM 10298c2ecf20Sopenharmony_ci // cycle 0 10308c2ecf20Sopenharmony_ci { .mii 10318c2ecf20Sopenharmony_ci alloc loc0=ar.pfs,2,Nregs-2,2,0 10328c2ecf20Sopenharmony_ci cmp.lt pRecurse,p0=Nregs*8,in0 // if more than Nregs regs left to clear, (re)curse 10338c2ecf20Sopenharmony_ci add out0=-Nregs*8,in0 10348c2ecf20Sopenharmony_ci}{ .mfb 10358c2ecf20Sopenharmony_ci add out1=1,in1 // increment recursion count 10368c2ecf20Sopenharmony_ci nop.f 0 10378c2ecf20Sopenharmony_ci nop.b 0 // can't do br.call here because of alloc (WAW on CFM) 10388c2ecf20Sopenharmony_ci ;; 10398c2ecf20Sopenharmony_ci}{ .mfi // cycle 1 10408c2ecf20Sopenharmony_ci mov loc1=0 10418c2ecf20Sopenharmony_ci nop.f 0 10428c2ecf20Sopenharmony_ci mov loc2=0 10438c2ecf20Sopenharmony_ci}{ .mib 10448c2ecf20Sopenharmony_ci mov loc3=0 10458c2ecf20Sopenharmony_ci mov loc4=0 10468c2ecf20Sopenharmony_ci(pRecurse) br.call.sptk.many b0=rse_clear_invalid 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci}{ .mfi // cycle 2 10498c2ecf20Sopenharmony_ci mov loc5=0 10508c2ecf20Sopenharmony_ci nop.f 0 10518c2ecf20Sopenharmony_ci cmp.ne pReturn,p0=r0,in1 // if recursion count != 0, we need to do a br.ret 10528c2ecf20Sopenharmony_ci}{ .mib 10538c2ecf20Sopenharmony_ci mov loc6=0 10548c2ecf20Sopenharmony_ci mov loc7=0 10558c2ecf20Sopenharmony_ci(pReturn) br.ret.sptk.many b0 10568c2ecf20Sopenharmony_ci} 10578c2ecf20Sopenharmony_ci#else /* !CONFIG_ITANIUM */ 10588c2ecf20Sopenharmony_ci alloc loc0=ar.pfs,2,Nregs-2,2,0 10598c2ecf20Sopenharmony_ci cmp.lt pRecurse,p0=Nregs*8,in0 // if more than Nregs regs left to clear, (re)curse 10608c2ecf20Sopenharmony_ci add out0=-Nregs*8,in0 10618c2ecf20Sopenharmony_ci add out1=1,in1 // increment recursion count 10628c2ecf20Sopenharmony_ci mov loc1=0 10638c2ecf20Sopenharmony_ci mov loc2=0 10648c2ecf20Sopenharmony_ci ;; 10658c2ecf20Sopenharmony_ci mov loc3=0 10668c2ecf20Sopenharmony_ci mov loc4=0 10678c2ecf20Sopenharmony_ci mov loc5=0 10688c2ecf20Sopenharmony_ci mov loc6=0 10698c2ecf20Sopenharmony_ci mov loc7=0 10708c2ecf20Sopenharmony_ci(pRecurse) br.call.dptk.few b0=rse_clear_invalid 10718c2ecf20Sopenharmony_ci ;; 10728c2ecf20Sopenharmony_ci mov loc8=0 10738c2ecf20Sopenharmony_ci mov loc9=0 10748c2ecf20Sopenharmony_ci cmp.ne pReturn,p0=r0,in1 // if recursion count != 0, we need to do a br.ret 10758c2ecf20Sopenharmony_ci mov loc10=0 10768c2ecf20Sopenharmony_ci mov loc11=0 10778c2ecf20Sopenharmony_ci(pReturn) br.ret.dptk.many b0 10788c2ecf20Sopenharmony_ci#endif /* !CONFIG_ITANIUM */ 10798c2ecf20Sopenharmony_ci# undef pRecurse 10808c2ecf20Sopenharmony_ci# undef pReturn 10818c2ecf20Sopenharmony_ci ;; 10828c2ecf20Sopenharmony_ci alloc r17=ar.pfs,0,0,0,0 // drop current register frame 10838c2ecf20Sopenharmony_ci ;; 10848c2ecf20Sopenharmony_ci loadrs 10858c2ecf20Sopenharmony_ci ;; 10868c2ecf20Sopenharmony_ciskip_rbs_switch: 10878c2ecf20Sopenharmony_ci mov ar.unat=r25 // M2 10888c2ecf20Sopenharmony_ci(pKStk) extr.u r22=r22,21,1 // I0 extract current value of psr.pp from r22 10898c2ecf20Sopenharmony_ci(pLvSys)mov r19=r0 // A clear r19 for leave_syscall, no-op otherwise 10908c2ecf20Sopenharmony_ci ;; 10918c2ecf20Sopenharmony_ci(pUStk) mov ar.bspstore=r23 // M2 10928c2ecf20Sopenharmony_ci(pKStk) dep r29=r22,r29,21,1 // I0 update ipsr.pp with psr.pp 10938c2ecf20Sopenharmony_ci(pLvSys)mov r16=r0 // A clear r16 for leave_syscall, no-op otherwise 10948c2ecf20Sopenharmony_ci ;; 10958c2ecf20Sopenharmony_ci MOV_TO_IPSR(p0, r29, r25) // M2 10968c2ecf20Sopenharmony_ci mov ar.pfs=r26 // I0 10978c2ecf20Sopenharmony_ci(pLvSys)mov r17=r0 // A clear r17 for leave_syscall, no-op otherwise 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci MOV_TO_IFS(p9, r30, r25)// M2 11008c2ecf20Sopenharmony_ci mov b0=r21 // I0 11018c2ecf20Sopenharmony_ci(pLvSys)mov r18=r0 // A clear r18 for leave_syscall, no-op otherwise 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci mov ar.fpsr=r20 // M2 11048c2ecf20Sopenharmony_ci MOV_TO_IIP(r28, r25) // M2 11058c2ecf20Sopenharmony_ci nop 0 11068c2ecf20Sopenharmony_ci ;; 11078c2ecf20Sopenharmony_ci(pUStk) mov ar.rnat=r24 // M2 must happen with RSE in lazy mode 11088c2ecf20Sopenharmony_ci nop 0 11098c2ecf20Sopenharmony_ci(pLvSys)mov r2=r0 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci mov ar.rsc=r27 // M2 11128c2ecf20Sopenharmony_ci mov pr=r31,-1 // I0 11138c2ecf20Sopenharmony_ci RFI // B 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci /* 11168c2ecf20Sopenharmony_ci * On entry: 11178c2ecf20Sopenharmony_ci * r20 = ¤t->thread_info->pre_count (if CONFIG_PREEMPTION) 11188c2ecf20Sopenharmony_ci * r31 = current->thread_info->flags 11198c2ecf20Sopenharmony_ci * On exit: 11208c2ecf20Sopenharmony_ci * p6 = TRUE if work-pending-check needs to be redone 11218c2ecf20Sopenharmony_ci * 11228c2ecf20Sopenharmony_ci * Interrupts are disabled on entry, reenabled depend on work, and 11238c2ecf20Sopenharmony_ci * disabled on exit. 11248c2ecf20Sopenharmony_ci */ 11258c2ecf20Sopenharmony_ci.work_pending_syscall: 11268c2ecf20Sopenharmony_ci add r2=-8,r2 11278c2ecf20Sopenharmony_ci add r3=-8,r3 11288c2ecf20Sopenharmony_ci ;; 11298c2ecf20Sopenharmony_ci st8 [r2]=r8 11308c2ecf20Sopenharmony_ci st8 [r3]=r10 11318c2ecf20Sopenharmony_ci.work_pending: 11328c2ecf20Sopenharmony_ci tbit.z p6,p0=r31,TIF_NEED_RESCHED // is resched not needed? 11338c2ecf20Sopenharmony_ci(p6) br.cond.sptk.few .notify 11348c2ecf20Sopenharmony_ci br.call.spnt.many rp=preempt_schedule_irq 11358c2ecf20Sopenharmony_ci.ret9: cmp.eq p6,p0=r0,r0 // p6 <- 1 (re-check) 11368c2ecf20Sopenharmony_ci(pLvSys)br.cond.sptk.few ia64_work_pending_syscall_end 11378c2ecf20Sopenharmony_ci br.cond.sptk.many .work_processed_kernel 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci.notify: 11408c2ecf20Sopenharmony_ci(pUStk) br.call.spnt.many rp=notify_resume_user 11418c2ecf20Sopenharmony_ci.ret10: cmp.ne p6,p0=r0,r0 // p6 <- 0 (don't re-check) 11428c2ecf20Sopenharmony_ci(pLvSys)br.cond.sptk.few ia64_work_pending_syscall_end 11438c2ecf20Sopenharmony_ci br.cond.sptk.many .work_processed_kernel 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci.global ia64_work_pending_syscall_end; 11468c2ecf20Sopenharmony_ciia64_work_pending_syscall_end: 11478c2ecf20Sopenharmony_ci adds r2=PT(R8)+16,r12 11488c2ecf20Sopenharmony_ci adds r3=PT(R10)+16,r12 11498c2ecf20Sopenharmony_ci ;; 11508c2ecf20Sopenharmony_ci ld8 r8=[r2] 11518c2ecf20Sopenharmony_ci ld8 r10=[r3] 11528c2ecf20Sopenharmony_ci br.cond.sptk.many ia64_work_processed_syscall 11538c2ecf20Sopenharmony_ciEND(ia64_leave_kernel) 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ciENTRY(handle_syscall_error) 11568c2ecf20Sopenharmony_ci /* 11578c2ecf20Sopenharmony_ci * Some system calls (e.g., ptrace, mmap) can return arbitrary values which could 11588c2ecf20Sopenharmony_ci * lead us to mistake a negative return value as a failed syscall. Those syscall 11598c2ecf20Sopenharmony_ci * must deposit a non-zero value in pt_regs.r8 to indicate an error. If 11608c2ecf20Sopenharmony_ci * pt_regs.r8 is zero, we assume that the call completed successfully. 11618c2ecf20Sopenharmony_ci */ 11628c2ecf20Sopenharmony_ci PT_REGS_UNWIND_INFO(0) 11638c2ecf20Sopenharmony_ci ld8 r3=[r2] // load pt_regs.r8 11648c2ecf20Sopenharmony_ci ;; 11658c2ecf20Sopenharmony_ci cmp.eq p6,p7=r3,r0 // is pt_regs.r8==0? 11668c2ecf20Sopenharmony_ci ;; 11678c2ecf20Sopenharmony_ci(p7) mov r10=-1 11688c2ecf20Sopenharmony_ci(p7) sub r8=0,r8 // negate return value to get errno 11698c2ecf20Sopenharmony_ci br.cond.sptk ia64_leave_syscall 11708c2ecf20Sopenharmony_ciEND(handle_syscall_error) 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci /* 11738c2ecf20Sopenharmony_ci * Invoke schedule_tail(task) while preserving in0-in7, which may be needed 11748c2ecf20Sopenharmony_ci * in case a system call gets restarted. 11758c2ecf20Sopenharmony_ci */ 11768c2ecf20Sopenharmony_ciGLOBAL_ENTRY(ia64_invoke_schedule_tail) 11778c2ecf20Sopenharmony_ci .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) 11788c2ecf20Sopenharmony_ci alloc loc1=ar.pfs,8,2,1,0 11798c2ecf20Sopenharmony_ci mov loc0=rp 11808c2ecf20Sopenharmony_ci mov out0=r8 // Address of previous task 11818c2ecf20Sopenharmony_ci ;; 11828c2ecf20Sopenharmony_ci br.call.sptk.many rp=schedule_tail 11838c2ecf20Sopenharmony_ci.ret11: mov ar.pfs=loc1 11848c2ecf20Sopenharmony_ci mov rp=loc0 11858c2ecf20Sopenharmony_ci br.ret.sptk.many rp 11868c2ecf20Sopenharmony_ciEND(ia64_invoke_schedule_tail) 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci /* 11898c2ecf20Sopenharmony_ci * Setup stack and call do_notify_resume_user(), keeping interrupts 11908c2ecf20Sopenharmony_ci * disabled. 11918c2ecf20Sopenharmony_ci * 11928c2ecf20Sopenharmony_ci * Note that pSys and pNonSys need to be set up by the caller. 11938c2ecf20Sopenharmony_ci * We declare 8 input registers so the system call args get preserved, 11948c2ecf20Sopenharmony_ci * in case we need to restart a system call. 11958c2ecf20Sopenharmony_ci */ 11968c2ecf20Sopenharmony_ciGLOBAL_ENTRY(notify_resume_user) 11978c2ecf20Sopenharmony_ci .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) 11988c2ecf20Sopenharmony_ci alloc loc1=ar.pfs,8,2,3,0 // preserve all eight input regs in case of syscall restart! 11998c2ecf20Sopenharmony_ci mov r9=ar.unat 12008c2ecf20Sopenharmony_ci mov loc0=rp // save return address 12018c2ecf20Sopenharmony_ci mov out0=0 // there is no "oldset" 12028c2ecf20Sopenharmony_ci adds out1=8,sp // out1=&sigscratch->ar_pfs 12038c2ecf20Sopenharmony_ci(pSys) mov out2=1 // out2==1 => we're in a syscall 12048c2ecf20Sopenharmony_ci ;; 12058c2ecf20Sopenharmony_ci(pNonSys) mov out2=0 // out2==0 => not a syscall 12068c2ecf20Sopenharmony_ci .fframe 16 12078c2ecf20Sopenharmony_ci .spillsp ar.unat, 16 12088c2ecf20Sopenharmony_ci st8 [sp]=r9,-16 // allocate space for ar.unat and save it 12098c2ecf20Sopenharmony_ci st8 [out1]=loc1,-8 // save ar.pfs, out1=&sigscratch 12108c2ecf20Sopenharmony_ci .body 12118c2ecf20Sopenharmony_ci br.call.sptk.many rp=do_notify_resume_user 12128c2ecf20Sopenharmony_ci.ret15: .restore sp 12138c2ecf20Sopenharmony_ci adds sp=16,sp // pop scratch stack space 12148c2ecf20Sopenharmony_ci ;; 12158c2ecf20Sopenharmony_ci ld8 r9=[sp] // load new unat from sigscratch->scratch_unat 12168c2ecf20Sopenharmony_ci mov rp=loc0 12178c2ecf20Sopenharmony_ci ;; 12188c2ecf20Sopenharmony_ci mov ar.unat=r9 12198c2ecf20Sopenharmony_ci mov ar.pfs=loc1 12208c2ecf20Sopenharmony_ci br.ret.sptk.many rp 12218c2ecf20Sopenharmony_ciEND(notify_resume_user) 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ciENTRY(sys_rt_sigreturn) 12248c2ecf20Sopenharmony_ci PT_REGS_UNWIND_INFO(0) 12258c2ecf20Sopenharmony_ci /* 12268c2ecf20Sopenharmony_ci * Allocate 8 input registers since ptrace() may clobber them 12278c2ecf20Sopenharmony_ci */ 12288c2ecf20Sopenharmony_ci alloc r2=ar.pfs,8,0,1,0 12298c2ecf20Sopenharmony_ci .prologue 12308c2ecf20Sopenharmony_ci PT_REGS_SAVES(16) 12318c2ecf20Sopenharmony_ci adds sp=-16,sp 12328c2ecf20Sopenharmony_ci .body 12338c2ecf20Sopenharmony_ci cmp.eq pNonSys,pSys=r0,r0 // sigreturn isn't a normal syscall... 12348c2ecf20Sopenharmony_ci ;; 12358c2ecf20Sopenharmony_ci /* 12368c2ecf20Sopenharmony_ci * leave_kernel() restores f6-f11 from pt_regs, but since the streamlined 12378c2ecf20Sopenharmony_ci * syscall-entry path does not save them we save them here instead. Note: we 12388c2ecf20Sopenharmony_ci * don't need to save any other registers that are not saved by the stream-lined 12398c2ecf20Sopenharmony_ci * syscall path, because restore_sigcontext() restores them. 12408c2ecf20Sopenharmony_ci */ 12418c2ecf20Sopenharmony_ci adds r16=PT(F6)+32,sp 12428c2ecf20Sopenharmony_ci adds r17=PT(F7)+32,sp 12438c2ecf20Sopenharmony_ci ;; 12448c2ecf20Sopenharmony_ci stf.spill [r16]=f6,32 12458c2ecf20Sopenharmony_ci stf.spill [r17]=f7,32 12468c2ecf20Sopenharmony_ci ;; 12478c2ecf20Sopenharmony_ci stf.spill [r16]=f8,32 12488c2ecf20Sopenharmony_ci stf.spill [r17]=f9,32 12498c2ecf20Sopenharmony_ci ;; 12508c2ecf20Sopenharmony_ci stf.spill [r16]=f10 12518c2ecf20Sopenharmony_ci stf.spill [r17]=f11 12528c2ecf20Sopenharmony_ci adds out0=16,sp // out0 = &sigscratch 12538c2ecf20Sopenharmony_ci br.call.sptk.many rp=ia64_rt_sigreturn 12548c2ecf20Sopenharmony_ci.ret19: .restore sp,0 12558c2ecf20Sopenharmony_ci adds sp=16,sp 12568c2ecf20Sopenharmony_ci ;; 12578c2ecf20Sopenharmony_ci ld8 r9=[sp] // load new ar.unat 12588c2ecf20Sopenharmony_ci mov.sptk b7=r8,ia64_leave_kernel 12598c2ecf20Sopenharmony_ci ;; 12608c2ecf20Sopenharmony_ci mov ar.unat=r9 12618c2ecf20Sopenharmony_ci br.many b7 12628c2ecf20Sopenharmony_ciEND(sys_rt_sigreturn) 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ciGLOBAL_ENTRY(ia64_prepare_handle_unaligned) 12658c2ecf20Sopenharmony_ci .prologue 12668c2ecf20Sopenharmony_ci /* 12678c2ecf20Sopenharmony_ci * r16 = fake ar.pfs, we simply need to make sure privilege is still 0 12688c2ecf20Sopenharmony_ci */ 12698c2ecf20Sopenharmony_ci mov r16=r0 12708c2ecf20Sopenharmony_ci DO_SAVE_SWITCH_STACK 12718c2ecf20Sopenharmony_ci br.call.sptk.many rp=ia64_handle_unaligned // stack frame setup in ivt 12728c2ecf20Sopenharmony_ci.ret21: .body 12738c2ecf20Sopenharmony_ci DO_LOAD_SWITCH_STACK 12748c2ecf20Sopenharmony_ci br.cond.sptk.many rp // goes to ia64_leave_kernel 12758c2ecf20Sopenharmony_ciEND(ia64_prepare_handle_unaligned) 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci // 12788c2ecf20Sopenharmony_ci // unw_init_running(void (*callback)(info, arg), void *arg) 12798c2ecf20Sopenharmony_ci // 12808c2ecf20Sopenharmony_ci# define EXTRA_FRAME_SIZE ((UNW_FRAME_INFO_SIZE+15)&~15) 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ciGLOBAL_ENTRY(unw_init_running) 12838c2ecf20Sopenharmony_ci .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2) 12848c2ecf20Sopenharmony_ci alloc loc1=ar.pfs,2,3,3,0 12858c2ecf20Sopenharmony_ci ;; 12868c2ecf20Sopenharmony_ci ld8 loc2=[in0],8 12878c2ecf20Sopenharmony_ci mov loc0=rp 12888c2ecf20Sopenharmony_ci mov r16=loc1 12898c2ecf20Sopenharmony_ci DO_SAVE_SWITCH_STACK 12908c2ecf20Sopenharmony_ci .body 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2) 12938c2ecf20Sopenharmony_ci .fframe IA64_SWITCH_STACK_SIZE+EXTRA_FRAME_SIZE 12948c2ecf20Sopenharmony_ci SWITCH_STACK_SAVES(EXTRA_FRAME_SIZE) 12958c2ecf20Sopenharmony_ci adds sp=-EXTRA_FRAME_SIZE,sp 12968c2ecf20Sopenharmony_ci .body 12978c2ecf20Sopenharmony_ci ;; 12988c2ecf20Sopenharmony_ci adds out0=16,sp // &info 12998c2ecf20Sopenharmony_ci mov out1=r13 // current 13008c2ecf20Sopenharmony_ci adds out2=16+EXTRA_FRAME_SIZE,sp // &switch_stack 13018c2ecf20Sopenharmony_ci br.call.sptk.many rp=unw_init_frame_info 13028c2ecf20Sopenharmony_ci1: adds out0=16,sp // &info 13038c2ecf20Sopenharmony_ci mov b6=loc2 13048c2ecf20Sopenharmony_ci mov loc2=gp // save gp across indirect function call 13058c2ecf20Sopenharmony_ci ;; 13068c2ecf20Sopenharmony_ci ld8 gp=[in0] 13078c2ecf20Sopenharmony_ci mov out1=in1 // arg 13088c2ecf20Sopenharmony_ci br.call.sptk.many rp=b6 // invoke the callback function 13098c2ecf20Sopenharmony_ci1: mov gp=loc2 // restore gp 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci // For now, we don't allow changing registers from within 13128c2ecf20Sopenharmony_ci // unw_init_running; if we ever want to allow that, we'd 13138c2ecf20Sopenharmony_ci // have to do a load_switch_stack here: 13148c2ecf20Sopenharmony_ci .restore sp 13158c2ecf20Sopenharmony_ci adds sp=IA64_SWITCH_STACK_SIZE+EXTRA_FRAME_SIZE,sp 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci mov ar.pfs=loc1 13188c2ecf20Sopenharmony_ci mov rp=loc0 13198c2ecf20Sopenharmony_ci br.ret.sptk.many rp 13208c2ecf20Sopenharmony_ciEND(unw_init_running) 13218c2ecf20Sopenharmony_ciEXPORT_SYMBOL(unw_init_running) 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci#ifdef CONFIG_FUNCTION_TRACER 13248c2ecf20Sopenharmony_ci#ifdef CONFIG_DYNAMIC_FTRACE 13258c2ecf20Sopenharmony_ciGLOBAL_ENTRY(_mcount) 13268c2ecf20Sopenharmony_ci br ftrace_stub 13278c2ecf20Sopenharmony_ciEND(_mcount) 13288c2ecf20Sopenharmony_ciEXPORT_SYMBOL(_mcount) 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci.here: 13318c2ecf20Sopenharmony_ci br.ret.sptk.many b0 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ciGLOBAL_ENTRY(ftrace_caller) 13348c2ecf20Sopenharmony_ci alloc out0 = ar.pfs, 8, 0, 4, 0 13358c2ecf20Sopenharmony_ci mov out3 = r0 13368c2ecf20Sopenharmony_ci ;; 13378c2ecf20Sopenharmony_ci mov out2 = b0 13388c2ecf20Sopenharmony_ci add r3 = 0x20, r3 13398c2ecf20Sopenharmony_ci mov out1 = r1; 13408c2ecf20Sopenharmony_ci br.call.sptk.many b0 = ftrace_patch_gp 13418c2ecf20Sopenharmony_ci //this might be called from module, so we must patch gp 13428c2ecf20Sopenharmony_ciftrace_patch_gp: 13438c2ecf20Sopenharmony_ci movl gp=__gp 13448c2ecf20Sopenharmony_ci mov b0 = r3 13458c2ecf20Sopenharmony_ci ;; 13468c2ecf20Sopenharmony_ci.global ftrace_call; 13478c2ecf20Sopenharmony_ciftrace_call: 13488c2ecf20Sopenharmony_ci{ 13498c2ecf20Sopenharmony_ci .mlx 13508c2ecf20Sopenharmony_ci nop.m 0x0 13518c2ecf20Sopenharmony_ci movl r3 = .here;; 13528c2ecf20Sopenharmony_ci} 13538c2ecf20Sopenharmony_ci alloc loc0 = ar.pfs, 4, 4, 2, 0 13548c2ecf20Sopenharmony_ci ;; 13558c2ecf20Sopenharmony_ci mov loc1 = b0 13568c2ecf20Sopenharmony_ci mov out0 = b0 13578c2ecf20Sopenharmony_ci mov loc2 = r8 13588c2ecf20Sopenharmony_ci mov loc3 = r15 13598c2ecf20Sopenharmony_ci ;; 13608c2ecf20Sopenharmony_ci adds out0 = -MCOUNT_INSN_SIZE, out0 13618c2ecf20Sopenharmony_ci mov out1 = in2 13628c2ecf20Sopenharmony_ci mov b6 = r3 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci br.call.sptk.many b0 = b6 13658c2ecf20Sopenharmony_ci ;; 13668c2ecf20Sopenharmony_ci mov ar.pfs = loc0 13678c2ecf20Sopenharmony_ci mov b0 = loc1 13688c2ecf20Sopenharmony_ci mov r8 = loc2 13698c2ecf20Sopenharmony_ci mov r15 = loc3 13708c2ecf20Sopenharmony_ci br ftrace_stub 13718c2ecf20Sopenharmony_ci ;; 13728c2ecf20Sopenharmony_ciEND(ftrace_caller) 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci#else 13758c2ecf20Sopenharmony_ciGLOBAL_ENTRY(_mcount) 13768c2ecf20Sopenharmony_ci movl r2 = ftrace_stub 13778c2ecf20Sopenharmony_ci movl r3 = ftrace_trace_function;; 13788c2ecf20Sopenharmony_ci ld8 r3 = [r3];; 13798c2ecf20Sopenharmony_ci ld8 r3 = [r3];; 13808c2ecf20Sopenharmony_ci cmp.eq p7,p0 = r2, r3 13818c2ecf20Sopenharmony_ci(p7) br.sptk.many ftrace_stub 13828c2ecf20Sopenharmony_ci ;; 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci alloc loc0 = ar.pfs, 4, 4, 2, 0 13858c2ecf20Sopenharmony_ci ;; 13868c2ecf20Sopenharmony_ci mov loc1 = b0 13878c2ecf20Sopenharmony_ci mov out0 = b0 13888c2ecf20Sopenharmony_ci mov loc2 = r8 13898c2ecf20Sopenharmony_ci mov loc3 = r15 13908c2ecf20Sopenharmony_ci ;; 13918c2ecf20Sopenharmony_ci adds out0 = -MCOUNT_INSN_SIZE, out0 13928c2ecf20Sopenharmony_ci mov out1 = in2 13938c2ecf20Sopenharmony_ci mov b6 = r3 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci br.call.sptk.many b0 = b6 13968c2ecf20Sopenharmony_ci ;; 13978c2ecf20Sopenharmony_ci mov ar.pfs = loc0 13988c2ecf20Sopenharmony_ci mov b0 = loc1 13998c2ecf20Sopenharmony_ci mov r8 = loc2 14008c2ecf20Sopenharmony_ci mov r15 = loc3 14018c2ecf20Sopenharmony_ci br ftrace_stub 14028c2ecf20Sopenharmony_ci ;; 14038c2ecf20Sopenharmony_ciEND(_mcount) 14048c2ecf20Sopenharmony_ci#endif 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ciGLOBAL_ENTRY(ftrace_stub) 14078c2ecf20Sopenharmony_ci mov r3 = b0 14088c2ecf20Sopenharmony_ci movl r2 = _mcount_ret_helper 14098c2ecf20Sopenharmony_ci ;; 14108c2ecf20Sopenharmony_ci mov b6 = r2 14118c2ecf20Sopenharmony_ci mov b7 = r3 14128c2ecf20Sopenharmony_ci br.ret.sptk.many b6 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci_mcount_ret_helper: 14158c2ecf20Sopenharmony_ci mov b0 = r42 14168c2ecf20Sopenharmony_ci mov r1 = r41 14178c2ecf20Sopenharmony_ci mov ar.pfs = r40 14188c2ecf20Sopenharmony_ci br b7 14198c2ecf20Sopenharmony_ciEND(ftrace_stub) 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci#endif /* CONFIG_FUNCTION_TRACER */ 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci#define __SYSCALL(nr, entry, nargs) data8 entry 14248c2ecf20Sopenharmony_ci .rodata 14258c2ecf20Sopenharmony_ci .align 8 14268c2ecf20Sopenharmony_ci .globl sys_call_table 14278c2ecf20Sopenharmony_cisys_call_table: 14288c2ecf20Sopenharmony_ci#include <asm/syscall_table.h> 14298c2ecf20Sopenharmony_ci#undef __SYSCALL 1430