Commit de387244 authored by David Mosberger's avatar David Mosberger

ia64: Implement a first cut of a streamlined fsys_fallback_syscall.

	Instead of using break, this one bubbles down into the kernel
	directly.  This code works, but isn't performance optimal yet.
parent 0c082819
...@@ -15,6 +15,9 @@ ...@@ -15,6 +15,9 @@
#include <asm/percpu.h> #include <asm/percpu.h>
#include <asm/thread_info.h> #include <asm/thread_info.h>
#include <asm/sal.h> #include <asm/sal.h>
#include <asm/system.h>
#include "entry.h"
/* /*
* See Documentation/ia64/fsys.txt for details on fsyscalls. * See Documentation/ia64/fsys.txt for details on fsyscalls.
...@@ -38,6 +41,58 @@ ...@@ -38,6 +41,58 @@
* ar.pfs = previous frame-state (as passed into the fsyscall handler) * ar.pfs = previous frame-state (as passed into the fsyscall handler)
*/ */
#if 1
ENTRY(fsys_fallback_syscall)
/*
* This is called for system calls which are entered via epc, but don't
* have a light-weight handler. We need to bubble down into the kernel,
* and that requires setting up a minimal pt_regs structure, and initializing
* the CPU state more or less as if an interruption had occurred. To make
* syscall-restarts work, we setup pt_regs such that cr_iip points to the
* second instruction in syscall_via_break. Decrementing the IP hence will
* restart the syscall via break and not decrementing IP will return us
* to the caller, as usual.
*/
# define PSR_PRESERVED_BITS (IA64_PSR_UP | IA64_PSR_MFL | IA64_PSR_MFH | IA64_PSR_PK \
| IA64_PSR_DT | IA64_PSR_RT)
/*
* Reading psr.l gives us only bits 0-31, psr.it, and psr.mc. The rest we have
* to synthesize.
*/
# define PSR_ONE_BITS ((3 << IA64_PSR_CPL0_BIT) | (0x1 << IA64_PSR_RI_BIT) \
| IA64_PSR_BN)
mov r29=psr
movl r9=PSR_PRESERVED_BITS
mov r20=r1
movl r8=PSR_ONE_BITS
;;
mov r1=IA64_KR(CURRENT) // r16 = current (physical); 12 cycle read lat.
and r9=r9,r29
or r29=r8,r29
;;
mov psr.l=r9 // slam the door
mov r21=ar.fpsr
mov r26=ar.pfs
mov r25=ar.unat
mov r27=ar.rsc
mov r19=b6
;;
srlz.i // ensure new psr.l has been established
movl r28=GATE_ADDR // cr.iip XXX fix me!! Should be: GATE_ADDR(syscall_via_break)
invala
mov r31=pr
adds r16=IA64_TASK_THREAD_ON_USTACK_OFFSET,r1
;;
st1 [r16]=r0 // clear current->thread.on_ustack flag
cmp.ne pKStk,pUStk=r0,r0 // set pKStk <- 0, pUStk <- 1
br.cond.sptk.many ia64_enter_syscall
END(fsys_fallback_syscall)
#endif
ENTRY(fsys_ni_syscall) ENTRY(fsys_ni_syscall)
mov r8=ENOSYS mov r8=ENOSYS
mov r10=-1 mov r10=-1
...@@ -334,7 +389,7 @@ fsyscall_table: ...@@ -334,7 +389,7 @@ fsyscall_table:
data8 fsys_fallback_syscall // chmod data8 fsys_fallback_syscall // chmod
data8 fsys_fallback_syscall // chown data8 fsys_fallback_syscall // chown
data8 fsys_fallback_syscall // lseek // 1040 data8 fsys_fallback_syscall // lseek // 1040
data8 fsys_getpid data8 fsys_getpid // getpid
data8 fsys_getppid // getppid data8 fsys_getppid // getppid
data8 fsys_fallback_syscall // mount data8 fsys_fallback_syscall // mount
data8 fsys_fallback_syscall // umount data8 fsys_fallback_syscall // umount
......
...@@ -21,6 +21,21 @@ ...@@ -21,6 +21,21 @@
#include <asm/errno.h> #include <asm/errno.h>
GLOBAL_ENTRY(syscall_via_break)
.prologue
.altrp b6
.body
/*
* Note: for (fast) syscall restart to work, the break instruction must be
* the first one in the bundle addressed by syscall_via_break.
*/
{ .mib
break 0x100000
nop.i 0
br.ret.sptk.many b6
}
END(syscall_via_break)
/* /*
* On entry: * On entry:
* r11 = saved ar.pfs * r11 = saved ar.pfs
...@@ -70,21 +85,7 @@ GLOBAL_ENTRY(syscall_via_epc) ...@@ -70,21 +85,7 @@ GLOBAL_ENTRY(syscall_via_epc)
br.ret.sptk.many b6 br.ret.sptk.many b6
END(syscall_via_epc) END(syscall_via_epc)
GLOBAL_ENTRY(syscall_via_break) #if 0
.prologue
.altrp b6
.body
/*
* Note: for (fast) syscall restart to work, the break instruction must be
* the first one in the bundle addressed by syscall_via_break.
*/
{ .mib
break 0x100000
nop.i 0
br.ret.sptk.many b6
}
END(syscall_via_break)
GLOBAL_ENTRY(fsys_fallback_syscall) GLOBAL_ENTRY(fsys_fallback_syscall)
/* /*
* It would be better/fsyser to do the SAVE_MIN magic directly here, but for now * It would be better/fsyser to do the SAVE_MIN magic directly here, but for now
...@@ -100,6 +101,7 @@ GLOBAL_ENTRY(fsys_fallback_syscall) ...@@ -100,6 +101,7 @@ GLOBAL_ENTRY(fsys_fallback_syscall)
mov b7=r2 mov b7=r2
br.ret.sptk.many b7 br.ret.sptk.many b7
END(fsys_fallback_syscall) END(fsys_fallback_syscall)
#endif
#endif /* CONFIG_FSYS */ #endif /* CONFIG_FSYS */
......
...@@ -637,6 +637,7 @@ END(daccess_bit) ...@@ -637,6 +637,7 @@ END(daccess_bit)
///////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////
// 0x2c00 Entry 11 (size 64 bundles) Break instruction (33) // 0x2c00 Entry 11 (size 64 bundles) Break instruction (33)
ENTRY(break_fault) ENTRY(break_fault)
.global ia64_enter_syscall
/* /*
* The streamlined system call entry/exit paths only save/restore the initial part * The streamlined system call entry/exit paths only save/restore the initial part
* of pt_regs. This implies that the callers of system-calls must adhere to the * of pt_regs. This implies that the callers of system-calls must adhere to the
...@@ -675,8 +676,22 @@ ENTRY(break_fault) ...@@ -675,8 +676,22 @@ ENTRY(break_fault)
adds r1=-IA64_TASK_THREAD_ON_USTACK_OFFSET,r16 // set r1 for MINSTATE_START_SAVE_MIN_VIRT adds r1=-IA64_TASK_THREAD_ON_USTACK_OFFSET,r16 // set r1 for MINSTATE_START_SAVE_MIN_VIRT
;; ;;
invala invala
/* adjust return address so we skip over the break instruction: */
extr.u r8=r29,41,2 // extract ei field from cr.ipsr
;;
cmp.eq p6,p7=2,r8 // isr.ei==2?
;;
(p6) mov r8=0 // clear ei to 0
(p6) adds r28=16,r28 // switch cr.iip to next bundle cr.ipsr.ei wrapped
(p7) adds r8=1,r8 // increment ei to next slot
;;
cmp.eq pKStk,pUStk=r0,r17 // are we in kernel mode already? cmp.eq pKStk,pUStk=r0,r17 // are we in kernel mode already?
dep r29=r8,r29,41,2 // insert new ei into cr.ipsr
;; ;;
ia64_enter_syscall:
// switch from user to kernel RBS: // switch from user to kernel RBS:
MINSTATE_START_SAVE_MIN_VIRT MINSTATE_START_SAVE_MIN_VIRT
br.call.sptk.many b7=setup_syscall_via_break br.call.sptk.many b7=setup_syscall_via_break
...@@ -692,33 +707,14 @@ ENTRY(break_fault) ...@@ -692,33 +707,14 @@ ENTRY(break_fault)
mov rp=r2 // set the real return addr mov rp=r2 // set the real return addr
;; ;;
(p7) add r20=(__NR_ni_syscall-1024)*8,r16 // force __NR_ni_syscall (p7) add r20=(__NR_ni_syscall-1024)*8,r16 // force __NR_ni_syscall
add r16=PT(CR_IPSR)+16,sp // get pointer to cr_ipsr
add r2=TI_FLAGS+IA64_TASK_SIZE,r13 add r2=TI_FLAGS+IA64_TASK_SIZE,r13
;; ;;
ld8 r20=[r20] // load address of syscall entry point ld8 r20=[r20] // load address of syscall entry point
ld8 r18=[r16] // fetch cr_ipsr
// arrange things so we skip over break instruction when returning:
adds r17=PT(CR_IIP)+16,sp // get pointer to cr_iip
;;
ld4 r2=[r2] // r2 = current_thread_info()->flags ld4 r2=[r2] // r2 = current_thread_info()->flags
ld8 r19=[r17] // fetch cr_iip
mov b6=r20
;;
extr.u r20=r18,41,2 // extract ei field
adds r19=16,r19 // compute address of next bundle
;;
cmp.eq p6,p7=2,r20 // isr.ei==2?
;; ;;
(p6) mov r20=0 // clear ei to 0
(p7) adds r20=1,r20 // increment ei to next slot
;;
(p6) st8 [r17]=r19 // store new cr.iip if cr.ipsr.ei wrapped around
dep r18=r20,r18,41,2 // insert new ei into cr.ipsr
tbit.z p8,p0=r2,TIF_SYSCALL_TRACE tbit.z p8,p0=r2,TIF_SYSCALL_TRACE
mov b6=r20
;; ;;
st8 [r16]=r18 // store new value for cr.ipsr
(p8) br.call.sptk.many b6=b6 // ignore this return addr (p8) br.call.sptk.many b6=b6 // ignore this return addr
br.cond.sptk ia64_trace_syscall br.cond.sptk ia64_trace_syscall
// NOT REACHED // NOT REACHED
...@@ -780,7 +776,7 @@ ENTRY(setup_syscall_via_break) ...@@ -780,7 +776,7 @@ ENTRY(setup_syscall_via_break)
add r16=PT(CR_IPSR),r1 // initialize first base pointer add r16=PT(CR_IPSR),r1 // initialize first base pointer
add r17=PT(R11),r1 // initialize second base pointer add r17=PT(R11),r1 // initialize second base pointer
;; ;;
alloc r19=ar.pfs,8,0,0,0 // ensur in0-in7 are writable alloc r19=ar.pfs,8,0,0,0 // ensure in0-in7 are writable
st8 [r16]=r29,PT(CR_IFS)-PT(CR_IPSR) // save cr.ipsr st8 [r16]=r29,PT(CR_IFS)-PT(CR_IPSR) // save cr.ipsr
tnat.nz p8,p0=in0 tnat.nz p8,p0=in0
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment