freebsd-dev/sys/ia64/ia64/syscall.S
Marcel Moolenaar 9d52656a5a Fix a nasty bug that got exposed when the sendsig() and sigreturn()
functions switched to using {g|s}et_mcontext(). The problem is that
sigreturn(), being a syscall, can be given an async. context (i.e.
one corresponding to an interrupt or trap). When this happens, we
try to return to user mode via epc_syscall_return with a trapframe
that can only be used to return to user mode via exception_restore.

To fix this, we check the frame's flags immediately prior to
epc_syscall_return and branch to exception_restore for non-syscall
frames. Modify the assertion in set_mcontext() to check that if
there's a mismatch, it's because of sigreturn().
2003-11-11 09:25:19 +00:00

570 lines
9.0 KiB
ArmAsm

/*
* Copyright (c) 2002, 2003 Marcel Moolenaar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/syscall.h>
#include <machine/asm.h>
#include <assym.s>
/*
* A process performs a syscall by performing an indirect call to the
* address stored in ar.k5. The contents of ar.pfs and rp should be
* saved prior to the syscall in r9 and r10 respectively. The kernel
* will restore these values on return. The value of gp is preserved
* across the call. This allows for small enough syscall stubs without
* getting too weird.
* The address in ar.k5 is the start of the EPC gateway page and also
* the syscall entry point. The syscall code in the gateway page is
* primarily responsible for increasing the privilege level, but will
* also make sure we have a reliable psr.
*
* A process defines:
* r8 - syscall number
* r9 - copy of ar.pfs
* r10 - copy of rp
* in0-in7 - syscall arguments
*
* A syscall returns:
* r8+r9 - syscall return value(s)
* r10 - syscall error flag
* ar.pfs - restored from r9
* rp - restored from r10
* gp - preserved
*
* The EPC syscall code defines:
* r11 - copy of psr.l
* r14 - Kernel memory stack
* r15 - Kernel register stack
*
* Also in the gateway page are the signal trampolines. As such, stacks
* don't have to be made executable per se. Since debuggers have a need
* to know about trampolines, we probably need to define a table of
* vectors or something along those lines so that debuggers can get the
* information they need and we have the freedom to move code around.
*/
.section .text.gateway, "ax"
.align PAGE_SIZE
.global ia64_gateway_page
ia64_gateway_page:
{ .mmb
mov r14=ar.k7 // Memory stack
mov r15=ar.k6 // Register stack
epc
;;
}
{ .mlx
mov r11=psr
movl r31=epc_syscall
;;
}
{ .mib
rum psr.be
mov b7=r31
br b7
;;
}
gw_ret:
{ .mmi
mov ar.rnat=r22
;;
mov ar.rsc=r24
mov ar.pfs=r20
}
{ .mib
mov ar.fpsr=r25
mov b0=r18
br.sptk b6
;;
}
gw_ret_ia32:
{ .mfb
flushrs
nop 0
nop 0
;;
}
{ .mfb
nop 0
nop 0
br.ia.sptk b6
;;
}
ENTRY(break_sigtramp, 0)
{ .mib
mov ar.rsc=0
cmp.ne p15,p0=0,gp
cover
;;
}
{ .mmi
flushrs
(p15) invala
add r16=16+UC_MCONTEXT+MC_SPECIAL,sp
;;
}
{ .mmi
mov r17=ar.bsp
mov r18=ar.rnat
add r14=40,r16
;;
}
{ .mmi
st8 [r14]=r17,64 // bspstore
(p15) mov ar.bspstore=gp
add r15=48,r16
;;
}
{ .mmi
st8 [r15]=r18 // rnat
st8 [r14]=r0 // ndirty
nop 0
;;
}
{ .mmi
alloc r14=ar.pfs, 0, 0, 3, 0
mov ar.rsc=15
mov out0=r8
;;
}
{ .mmi
ld8 r16=[r10],8 // function address
;;
ld8 gp=[r10] // function's gp value
mov b7=r16
;;
}
{ .mib
mov out1=r9
add out2=16,sp
br.call.sptk rp=b7
;;
}
{ .mmi
mov r15=SYS_sigreturn
add out0=16,sp
break 0x100000
;;
}
{ .mmi
mov r15=SYS_exit
mov out0=ret0
break 0x100000
;;
}
END(break_sigtramp)
ENTRY(epc_sigtramp, 0)
{ .mmi
ld8 r16=[r10],8 // function address
mov ar.rsc=0
cmp.ne p15,p0=0,gp
;;
}
{ .mmi
(p15) invala
(p15) mov ar.bspstore=gp
mov b7=r16
;;
}
{ .mmb
alloc r14=ar.pfs, 0, 0, 3, 0
mov ar.rsc=15
nop 0
;;
}
{ .mii
ld8 gp=[r10] // function's gp value
mov out0=r8
mov out1=r9
}
{ .mfb
add out2=16,sp
nop 0
br.call.sptk rp=b7
;;
}
add out0=16,sp
CALLSYS_NOERROR(sigreturn)
mov out0=ret0
CALLSYS_NOERROR(exit)
END(epc_sigtramp)
.align PAGE_SIZE
.text
ENTRY(epc_syscall, 8)
.prologue
.unwabi @svr4, 'E'
.save rp, r0
.body
{ .mmi
mov r16=ar.rsc
mov ar.rsc=0
mov r17=r13
;;
}
{ .mmi
mov r18=ar.bspstore
;;
mov r19=ar.rnat
dep r15=r18,r15,0,9
;;
}
{ .mmi
mov ar.bspstore=r15
add r30=-SIZEOF_TRAPFRAME,r14
mov r20=sp
;;
}
{ .mii
mov r13=ar.k4
dep r30=0,r30,0,10
;;
add sp=-16,r30
;;
}
{ .mib
mov r21=ar.unat
add r31=8,r30
nop 0
;;
}
{ .mib
mov r22=ar.fpsr
sub r29=r14,r30
nop 0
}
{ .mmi
mov r23=ar.bsp
mov ar.rsc=3
add r28=FRAME_SYSCALL,r0
;;
}
{ .mmi
st8 [r30]=r29,16 // tf_length
st8 [r31]=r28,16 // tf_flags
mov r24=rp
;;
}
{ .mmi
st8 [r30]=r20,16 // sp
st8 [r31]=r21,16 // unat
mov r25=pr
;;
}
{ .mmi
st8 [r30]=r10,16 // rp (syscall caller)
st8 [r31]=r25,16 // pr
mov r26=ar.pfs
;;
}
{ .mmi
st8 [r30]=r9,16 // pfs (syscall caller)
st8 [r31]=r18,16 // bspstore
sub r27=r23,r15
;;
}
{ .mmi
st8 [r30]=r19,16 // rnat
st8 [r31]=r0,16 // __spare
nop 0
;;
}
{ .mmi
st8 [r30]=r17,16 // tp
st8 [r31]=r16,16 // rsc
dep r11=-1,r11,32,2 // Set psr.cpl=3
;;
}
{ .mmi
st8 [r30]=r22,16 // fpsr
st8 [r31]=r11,16 // psr
nop 0
;;
}
{ .mmi
st8 [r30]=r1,16 // gp
st8 [r31]=r27,16 // ndirty
nop 0
;;
}
{ .mmi
st8 [r30]=r26,16 // pfs (syscall stub)
st8 [r31]=r24,16 // rp (syscall stub)
nop 0
;;
}
{ .mmi
st8 [r30]=r0,80 // ifa
st8 [r31]=r0,80 // isr
nop 0
;;
}
{ .mmi
alloc r14=ar.pfs,0,0,8,0
st8 [r30]=r8,16 // syscall number (=r15)
nop 0
;;
}
{ .mmi
.mem.offset 0,0
st8.spill [r31]=r32,16 // arg0 (=r16)
.mem.offset 8,0
st8.spill [r30]=r33,16 // arg1 (=r17)
nop 0
;;
}
{ .mmi
.mem.offset 16,0
st8.spill [r31]=r34,16 // arg2 (=r18)
.mem.offset 24,0
st8.spill [r30]=r35,16 // arg3 (=r19)
nop 0
;;
}
{ .mmi
.mem.offset 32,0
st8.spill [r31]=r36,16 // arg4 (=r20)
.mem.offset 40,0
st8.spill [r30]=r37,16 // arg5 (=r21)
nop 0
;;
}
{ .mmi
.mem.offset 48,0
st8.spill [r31]=r38 // arg6 (=r22)
.mem.offset 56,0
st8.spill [r30]=r39 // arg7 (=r23)
nop 0
;;
}
{ .mlx
ssm psr.dfh|psr.ac
movl gp=__gp
;;
}
1:
{ .mib
srlz.d
add out0=16,sp
br.call.sptk rp=syscall
;;
}
{ .mfb
add out0=16,sp
nop 0
br.call.sptk rp=do_ast
;;
}
{ .mib
cmp4.eq p15,p0=ERESTART,r8
add r14=24,sp
(p15) br.spnt 1b // restart syscall
;;
}
{ .mfb
ld8 r14=[r14] // tf_flags
nop 0
nop 0
;;
}
{ .mib
nop 0
tbit.z p15,p0=r14,0
(p15) br.spnt exception_restore
;;
}
.global epc_syscall_return
epc_syscall_return:
{ .mmi
alloc r31=ar.pfs,0,0,0,0
add r14=32,sp
add r15=16,sp
;;
}
{ .mmi
ld8 r31=[r15],24 // tf_length
ld8 r16=[r14],16 // sp
add sp=16,sp
;;
}
{ .mmi
ld8 r17=[r15],16 // unat (before)
ld8 r18=[r14],16 // rp (syscall caller)
add r31=r31,sp
;;
}
{ .mmb
ld8 r19=[r15],16 // pr
ld8 r20=[r14],16 // pfs (syscall caller)
nop 0
;;
}
{ .mmi
ld8 r21=[r15],24 // bspstore
ld8 r22=[r14],24 // rnat
mov pr=r19,0x1fffe
;;
}
{ .mmb
ld8 r23=[r15],16 // tp
ld8 r24=[r14],16 // rsc
nop 0
;;
}
{ .mmi
ld8 r25=[r15],16 // fpsr
ld8 r26=[r14],16 // psr
nop 0
;;
}
{ .mmi
ld8 gp=[r15],16 // gp
ld8 r27=[r14],16 // ndirty
tbit.z p14,p15=r26,34 // p14=ia64, p15=ia32
;;
}
{ .mmi
ld8 r28=[r15],56 // pfs (syscall stub)
ld8 r29=[r14],56 // rp (syscall stub)
shl r27=r27,16
;;
}
{ .mmi
ld8 r8=[r15],16 // r8
mov ar.rsc=r27
mov b6=r29
;;
}
{ .mmb
ld8 r9=[r14],40 // r9
ld8 r10=[r15],40 // r10
(p15) br.spnt epc_syscall_setup_ia32
;;
}
{ .mmi
loadrs
mov ar.k7=r31
mov sp=r16
;;
}
{ .mmi
mov r30=ar.bspstore
mov r14=ar.k5
mov ar.pfs=r28
;;
}
{ .mmi
mov ar.bspstore=r21
add r14=gw_ret-ia64_gateway_page,r14
dep r30=0,r30,0,13 // 8KB aligned.
;;
}
{ .mib
mov ar.k6=r30
mov r13=r23
nop 0
}
{ .mmi
mov psr.l=r26
mov ar.unat=r17
nop 0
;;
}
{ .mib
srlz.d
mov b7=r14
br.ret.sptk b7
;;
}
epc_syscall_setup_ia32:
{ .mmi
loadrs
mov ar.k7=r31
mov sp=r16
;;
}
{ .mmi
mov r30=ar.bspstore
;;
mov ar.unat=r17
dep r30=0,r30,0,13 // 8KB aligned
;;
}
{ .mmi
mov ar.k6=r30
mov ar.bspstore=r21
mov r11=r0
;;
}
{ .mmi
ld8 r16=[r14],64
ld8 r17=[r15],80
mov r13=r0
;;
}
ld8 r24=[r14],32
ld8 r27=[r15],16
;;
ld8 r28=[r14],16
ld8 r29=[r15],16
;;
ld8 r30=[r14],40
ld8 r31=[r15],40
;;
{ .mmi
ld8 r2=[r14]
ld8 r3=[r15]
mov r14=r0
;;
}
{ .mmi
mov ar.csd=r2
mov ar.ssd=r3
mov r15=r0
;;
}
mov r2=ar.k5
mov psr.l=r26
;;
srlz.d
add r2=gw_ret_ia32-ia64_gateway_page,r2
;;
mov ar.rsc=0x0
mov b7=r2
br.ret.sptk b7
;;
END(epc_syscall)