157 lines
3.5 KiB
ArmAsm
157 lines
3.5 KiB
ArmAsm
|
#define __NR_sigaction 67
|
||
|
#define SIG_BLOCK 0
|
||
|
#define SIG_SETMASK 2
|
||
|
#define MAXSIG 32
|
||
|
|
||
|
/* offsets into our stack frame */
|
||
|
#define mynew 16 /* new sigaction */
|
||
|
#define mynset 32 /* new signal set */
|
||
|
#define myoset 36 /* old signal set */
|
||
|
#define mysave 40
|
||
|
#define mysize 56
|
||
|
|
||
|
.sect .text; .sect .rodata; .sect .data; .sect .bss
|
||
|
|
||
|
/*
|
||
|
* Linux calls signal handlers with arguments in registers, but the
|
||
|
* ACK expects arguments on the stack. This sigaction() uses a
|
||
|
* "bridge" to move the arguments.
|
||
|
*/
|
||
|
.sect .text
|
||
|
.define _sigaction
|
||
|
_sigaction:
|
||
|
mflr r0
|
||
|
subi r1, r1, mysize
|
||
|
stw r31, mysave+8(r1)
|
||
|
stw r30, mysave+4(r1)
|
||
|
stw r29, mysave(r1)
|
||
|
stw r0, mysave+12(r1)
|
||
|
li r3, 0
|
||
|
stw r3, mynset(r1) ! mynset = 0
|
||
|
lwz r29, mysize(r1) ! r29 = signal number
|
||
|
lwz r30, mysize+4(r1) ! r30 = new action
|
||
|
lwz r31, mysize+8(r1) ! r31 = old action
|
||
|
/*
|
||
|
* If the new action is non-NULL, the signal number is in
|
||
|
* range 1 to MAXSIG, and the new handler is not SIG_DFL 0
|
||
|
* or SIG_IGN 1, then we interpose our bridge.
|
||
|
*/
|
||
|
cmpwi cr0, r30, 0
|
||
|
subi r7, r29, 1 ! r7 = index in handlers
|
||
|
cmplwi cr7, r7, MAXSIG ! unsigned comparison
|
||
|
beq cr0, kernel
|
||
|
bge cr7, kernel
|
||
|
lwz r3, 0(r30) ! r3 = new handler
|
||
|
clrrwi. r3, r3, 1
|
||
|
beq cr0, kernel
|
||
|
/*
|
||
|
* Block the signal while we build the bridge. Prevents a
|
||
|
* race if a signal arrives after we change the bridge but
|
||
|
* before we change the action in the kernel.
|
||
|
*/
|
||
|
li r4, 1
|
||
|
slw r4, r4, r7
|
||
|
stw r4, mynset(r1) ! mynmask = 1 << (signal - 1)
|
||
|
li r3, SIG_BLOCK
|
||
|
la r4, mynset(r1)
|
||
|
la r5, myoset(r1)
|
||
|
stw r3, 0(r1)
|
||
|
stw r4, 4(r1)
|
||
|
stw r5, 8(r1)
|
||
|
bl _sigprocmask
|
||
|
/*
|
||
|
* Point our bridge to the new signal handler. Then copy the
|
||
|
* new sigaction but point it to our bridge.
|
||
|
*/
|
||
|
lis r6, hi16[handlers]
|
||
|
ori r6, r6, lo16[handlers]
|
||
|
subi r7, r29, 1
|
||
|
slwi r7, r7, 2
|
||
|
lwz r3, 0(r30) ! r3 = new handler
|
||
|
stwx r3, r6, r7 ! put it in array of handlers
|
||
|
lis r3, hi16[bridge]
|
||
|
ori r3, r3, lo16[bridge]
|
||
|
lwz r4, 4(r30)
|
||
|
lwz r5, 8(r30)
|
||
|
lwz r6, 12(r30)
|
||
|
stw r3, mynew(r1) ! sa_handler or sa_sigaction
|
||
|
stw r4, mynew+4(r1) ! sa_mask
|
||
|
stw r5, mynew+8(r1) ! sa_flags
|
||
|
stw r6, mynew+12(r1) ! sa_restorer
|
||
|
la r30, mynew(r1)
|
||
|
kernel:
|
||
|
li r3, __NR_sigaction
|
||
|
stw r3, 0(r1)
|
||
|
stw r29, 4(r1)
|
||
|
stw r30, 8(r1)
|
||
|
stw r31, 12(r1)
|
||
|
bl __syscall
|
||
|
/*
|
||
|
* If we blocked the signal, then restore the old signal mask.
|
||
|
*/
|
||
|
lwz r3, mynset(r1)
|
||
|
cmpwi cr0, r3, 0
|
||
|
beq cr0, fixold
|
||
|
li r3, SIG_SETMASK
|
||
|
la r4, myoset(r1)
|
||
|
li r5, 0
|
||
|
stw r3, 0(r1)
|
||
|
stw r4, 4(r1)
|
||
|
stw r5, 8(r1)
|
||
|
bl _sigprocmask
|
||
|
/*
|
||
|
* If the old sigaction is non-NULL and points to our bridge,
|
||
|
* then point it to the signal handler.
|
||
|
*/
|
||
|
fixold:
|
||
|
cmpwi cr0, r31, 0
|
||
|
beq cr0, leave
|
||
|
lis r3, hi16[bridge]
|
||
|
ori r3, r3, lo16[bridge]
|
||
|
lwz r4, 0(r31)
|
||
|
cmpw cr0, r3, r4
|
||
|
bne cr0, leave
|
||
|
lis r6, hi16[handlers]
|
||
|
ori r6, r6, lo16[handlers]
|
||
|
subi r7, r29, 1
|
||
|
slwi r7, r7, 2
|
||
|
lwzx r3, r6, r7 ! get it from array of handlers
|
||
|
stw r3, 0(r31) ! put it in old sigaction
|
||
|
leave:
|
||
|
lwz r0, mysave+12(r1)
|
||
|
lwz r29, mysave(r1)
|
||
|
lwz r30, mysave+4(r1)
|
||
|
lwz r31, mysave+8(r1)
|
||
|
addi r1, r1, mysize
|
||
|
mtlr r0
|
||
|
blr ! return from sigaction
|
||
|
|
||
|
/*
|
||
|
* Linux calls bridge(signum) or bridge(signum, info, context) with
|
||
|
* arguments in registers r3, r4, r5.
|
||
|
*/
|
||
|
bridge:
|
||
|
mflr r0
|
||
|
subi r1, r1, 16
|
||
|
stw r0, 12(r1)
|
||
|
stw r3, 0(r1) ! signal number
|
||
|
stw r4, 4(r1) ! info
|
||
|
stw r5, 8(r1) ! context
|
||
|
|
||
|
lis r6, hi16[handlers]
|
||
|
ori r6, r6, lo16[handlers]
|
||
|
subi r7, r3, 1
|
||
|
slwi r7, r7, 2
|
||
|
lwzx r6, r6, r7
|
||
|
mtctr r6
|
||
|
bctrl ! call our signal handler
|
||
|
|
||
|
lwz r0, 12(r1)
|
||
|
addi r1, r1, 16
|
||
|
mtlr r0
|
||
|
blr ! return from bridge
|
||
|
|
||
|
.sect .bss
|
||
|
handlers:
|
||
|
.space 4 * MAXSIG ! array of signal handlers
|