aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ia64/kernel/gate.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ia64/kernel/gate.S')
-rw-r--r--arch/ia64/kernel/gate.S171
1 files changed, 90 insertions, 81 deletions
diff --git a/arch/ia64/kernel/gate.S b/arch/ia64/kernel/gate.S
index 74b1ccce4e8..cf5e0a105e1 100644
--- a/arch/ia64/kernel/gate.S
+++ b/arch/ia64/kernel/gate.S
@@ -13,6 +13,7 @@
13#include <asm/sigcontext.h> 13#include <asm/sigcontext.h>
14#include <asm/system.h> 14#include <asm/system.h>
15#include <asm/unistd.h> 15#include <asm/unistd.h>
16#include "paravirt_inst.h"
16 17
17/* 18/*
18 * We can't easily refer to symbols inside the kernel. To avoid full runtime relocation, 19 * We can't easily refer to symbols inside the kernel. To avoid full runtime relocation,
@@ -48,87 +49,6 @@ GLOBAL_ENTRY(__kernel_syscall_via_break)
48} 49}
49END(__kernel_syscall_via_break) 50END(__kernel_syscall_via_break)
50 51
51/*
52 * On entry:
53 * r11 = saved ar.pfs
54 * r15 = system call #
55 * b0 = saved return address
56 * b6 = return address
57 * On exit:
58 * r11 = saved ar.pfs
59 * r15 = system call #
60 * b0 = saved return address
61 * all other "scratch" registers: undefined
62 * all "preserved" registers: same as on entry
63 */
64
65GLOBAL_ENTRY(__kernel_syscall_via_epc)
66 .prologue
67 .altrp b6
68 .body
69{
70 /*
71 * Note: the kernel cannot assume that the first two instructions in this
72 * bundle get executed. The remaining code must be safe even if
73 * they do not get executed.
74 */
75 adds r17=-1024,r15 // A
76 mov r10=0 // A default to successful syscall execution
77 epc // B causes split-issue
78}
79 ;;
80 rsm psr.be | psr.i // M2 (5 cyc to srlz.d)
81 LOAD_FSYSCALL_TABLE(r14) // X
82 ;;
83 mov r16=IA64_KR(CURRENT) // M2 (12 cyc)
84 shladd r18=r17,3,r14 // A
85 mov r19=NR_syscalls-1 // A
86 ;;
87 lfetch [r18] // M0|1
88 mov r29=psr // M2 (12 cyc)
89 // If r17 is a NaT, p6 will be zero
90 cmp.geu p6,p7=r19,r17 // A (sysnr > 0 && sysnr < 1024+NR_syscalls)?
91 ;;
92 mov r21=ar.fpsr // M2 (12 cyc)
93 tnat.nz p10,p9=r15 // I0
94 mov.i r26=ar.pfs // I0 (would stall anyhow due to srlz.d...)
95 ;;
96 srlz.d // M0 (forces split-issue) ensure PSR.BE==0
97(p6) ld8 r18=[r18] // M0|1
98 nop.i 0
99 ;;
100 nop.m 0
101(p6) tbit.z.unc p8,p0=r18,0 // I0 (dual-issues with "mov b7=r18"!)
102 nop.i 0
103 ;;
104(p8) ssm psr.i
105(p6) mov b7=r18 // I0
106(p8) br.dptk.many b7 // B
107
108 mov r27=ar.rsc // M2 (12 cyc)
109/*
110 * brl.cond doesn't work as intended because the linker would convert this branch
111 * into a branch to a PLT. Perhaps there will be a way to avoid this with some
112 * future version of the linker. In the meantime, we just use an indirect branch
113 * instead.
114 */
115#ifdef CONFIG_ITANIUM
116(p6) add r14=-8,r14 // r14 <- addr of fsys_bubble_down entry
117 ;;
118(p6) ld8 r14=[r14] // r14 <- fsys_bubble_down
119 ;;
120(p6) mov b7=r14
121(p6) br.sptk.many b7
122#else
123 BRL_COND_FSYS_BUBBLE_DOWN(p6)
124#endif
125 ssm psr.i
126 mov r10=-1
127(p10) mov r8=EINVAL
128(p9) mov r8=ENOSYS
129 FSYS_RETURN
130END(__kernel_syscall_via_epc)
131
132# define ARG0_OFF (16 + IA64_SIGFRAME_ARG0_OFFSET) 52# define ARG0_OFF (16 + IA64_SIGFRAME_ARG0_OFFSET)
133# define ARG1_OFF (16 + IA64_SIGFRAME_ARG1_OFFSET) 53# define ARG1_OFF (16 + IA64_SIGFRAME_ARG1_OFFSET)
134# define ARG2_OFF (16 + IA64_SIGFRAME_ARG2_OFFSET) 54# define ARG2_OFF (16 + IA64_SIGFRAME_ARG2_OFFSET)
@@ -374,3 +294,92 @@ restore_rbs:
374 // invala not necessary as that will happen when returning to user-mode 294 // invala not necessary as that will happen when returning to user-mode
375 br.cond.sptk back_from_restore_rbs 295 br.cond.sptk back_from_restore_rbs
376END(__kernel_sigtramp) 296END(__kernel_sigtramp)
297
298/*
299 * On entry:
300 * r11 = saved ar.pfs
301 * r15 = system call #
302 * b0 = saved return address
303 * b6 = return address
304 * On exit:
305 * r11 = saved ar.pfs
306 * r15 = system call #
307 * b0 = saved return address
308 * all other "scratch" registers: undefined
309 * all "preserved" registers: same as on entry
310 */
311
312GLOBAL_ENTRY(__kernel_syscall_via_epc)
313 .prologue
314 .altrp b6
315 .body
316{
317 /*
318 * Note: the kernel cannot assume that the first two instructions in this
319 * bundle get executed. The remaining code must be safe even if
320 * they do not get executed.
321 */
322 adds r17=-1024,r15 // A
323 mov r10=0 // A default to successful syscall execution
324 epc // B causes split-issue
325}
326 ;;
327 RSM_PSR_BE_I(r20, r22) // M2 (5 cyc to srlz.d)
328 LOAD_FSYSCALL_TABLE(r14) // X
329 ;;
330 mov r16=IA64_KR(CURRENT) // M2 (12 cyc)
331 shladd r18=r17,3,r14 // A
332 mov r19=NR_syscalls-1 // A
333 ;;
334 lfetch [r18] // M0|1
335 MOV_FROM_PSR(p0, r29, r8) // M2 (12 cyc)
336 // If r17 is a NaT, p6 will be zero
337 cmp.geu p6,p7=r19,r17 // A (sysnr > 0 && sysnr < 1024+NR_syscalls)?
338 ;;
339 mov r21=ar.fpsr // M2 (12 cyc)
340 tnat.nz p10,p9=r15 // I0
341 mov.i r26=ar.pfs // I0 (would stall anyhow due to srlz.d...)
342 ;;
343 srlz.d // M0 (forces split-issue) ensure PSR.BE==0
344(p6) ld8 r18=[r18] // M0|1
345 nop.i 0
346 ;;
347 nop.m 0
348(p6) tbit.z.unc p8,p0=r18,0 // I0 (dual-issues with "mov b7=r18"!)
349 nop.i 0
350 ;;
351 SSM_PSR_I(p8, p14, r25)
352(p6) mov b7=r18 // I0
353(p8) br.dptk.many b7 // B
354
355 mov r27=ar.rsc // M2 (12 cyc)
356/*
357 * brl.cond doesn't work as intended because the linker would convert this branch
358 * into a branch to a PLT. Perhaps there will be a way to avoid this with some
359 * future version of the linker. In the meantime, we just use an indirect branch
360 * instead.
361 */
362#ifdef CONFIG_ITANIUM
363(p6) add r14=-8,r14 // r14 <- addr of fsys_bubble_down entry
364 ;;
365(p6) ld8 r14=[r14] // r14 <- fsys_bubble_down
366 ;;
367(p6) mov b7=r14
368(p6) br.sptk.many b7
369#else
370 BRL_COND_FSYS_BUBBLE_DOWN(p6)
371#endif
372 SSM_PSR_I(p0, p14, r10)
373 mov r10=-1
374(p10) mov r8=EINVAL
375(p9) mov r8=ENOSYS
376 FSYS_RETURN
377
378#ifdef CONFIG_PARAVIRT
379 /*
380 * padd to make the size of this symbol constant
381 * independent of paravirtualization.
382 */
383 .align PAGE_SIZE / 8
384#endif
385END(__kernel_syscall_via_epc)