1*433d6423SLionel Sambuc /* The kernel call that is implemented in this file:
2*433d6423SLionel Sambuc * m_type: SYS_SIGSEND
3*433d6423SLionel Sambuc *
4*433d6423SLionel Sambuc * The parameters for this kernel call are:
5*433d6423SLionel Sambuc * m_sigcalls.endpt # process to call signal handler
6*433d6423SLionel Sambuc * m_sigcalls.sigctx # pointer to sigcontext structure
7*433d6423SLionel Sambuc *
8*433d6423SLionel Sambuc */
9*433d6423SLionel Sambuc
10*433d6423SLionel Sambuc #include "kernel/system.h"
11*433d6423SLionel Sambuc #include <signal.h>
12*433d6423SLionel Sambuc #include <string.h>
13*433d6423SLionel Sambuc
14*433d6423SLionel Sambuc #if USE_SIGSEND
15*433d6423SLionel Sambuc
16*433d6423SLionel Sambuc /*===========================================================================*
17*433d6423SLionel Sambuc * do_sigsend *
18*433d6423SLionel Sambuc *===========================================================================*/
do_sigsend(struct proc * caller,message * m_ptr)19*433d6423SLionel Sambuc int do_sigsend(struct proc * caller, message * m_ptr)
20*433d6423SLionel Sambuc {
21*433d6423SLionel Sambuc /* Handle sys_sigsend, POSIX-style signal handling. */
22*433d6423SLionel Sambuc
23*433d6423SLionel Sambuc struct sigmsg smsg;
24*433d6423SLionel Sambuc register struct proc *rp;
25*433d6423SLionel Sambuc struct sigframe_sigcontext fr, *frp;
26*433d6423SLionel Sambuc int proc_nr, r;
27*433d6423SLionel Sambuc #if defined(__i386__)
28*433d6423SLionel Sambuc reg_t new_fp;
29*433d6423SLionel Sambuc #endif
30*433d6423SLionel Sambuc
31*433d6423SLionel Sambuc if (!isokendpt(m_ptr->m_sigcalls.endpt, &proc_nr)) return EINVAL;
32*433d6423SLionel Sambuc if (iskerneln(proc_nr)) return EPERM;
33*433d6423SLionel Sambuc rp = proc_addr(proc_nr);
34*433d6423SLionel Sambuc
35*433d6423SLionel Sambuc /* Get the sigmsg structure into our address space. */
36*433d6423SLionel Sambuc if ((r = data_copy_vmcheck(caller, caller->p_endpoint,
37*433d6423SLionel Sambuc (vir_bytes)m_ptr->m_sigcalls.sigctx, KERNEL,
38*433d6423SLionel Sambuc (vir_bytes)&smsg, (phys_bytes) sizeof(struct sigmsg))) != OK)
39*433d6423SLionel Sambuc return r;
40*433d6423SLionel Sambuc
41*433d6423SLionel Sambuc /* WARNING: the following code may be run more than once even for a single
42*433d6423SLionel Sambuc * signal delivery. Do not change registers here. See the comment below.
43*433d6423SLionel Sambuc */
44*433d6423SLionel Sambuc
45*433d6423SLionel Sambuc /* Compute the user stack pointer where sigframe will start. */
46*433d6423SLionel Sambuc smsg.sm_stkptr = arch_get_sp(rp);
47*433d6423SLionel Sambuc frp = (struct sigframe_sigcontext *) smsg.sm_stkptr - 1;
48*433d6423SLionel Sambuc
49*433d6423SLionel Sambuc /* Copy the registers to the sigcontext structure. */
50*433d6423SLionel Sambuc memset(&fr, 0, sizeof(fr));
51*433d6423SLionel Sambuc fr.sf_scp = &frp->sf_sc;
52*433d6423SLionel Sambuc
53*433d6423SLionel Sambuc #if defined(__i386__)
54*433d6423SLionel Sambuc fr.sf_sc.sc_gs = rp->p_reg.gs;
55*433d6423SLionel Sambuc fr.sf_sc.sc_fs = rp->p_reg.fs;
56*433d6423SLionel Sambuc fr.sf_sc.sc_es = rp->p_reg.es;
57*433d6423SLionel Sambuc fr.sf_sc.sc_ds = rp->p_reg.ds;
58*433d6423SLionel Sambuc fr.sf_sc.sc_edi = rp->p_reg.di;
59*433d6423SLionel Sambuc fr.sf_sc.sc_esi = rp->p_reg.si;
60*433d6423SLionel Sambuc fr.sf_sc.sc_ebp = rp->p_reg.fp;
61*433d6423SLionel Sambuc fr.sf_sc.sc_ebx = rp->p_reg.bx;
62*433d6423SLionel Sambuc fr.sf_sc.sc_edx = rp->p_reg.dx;
63*433d6423SLionel Sambuc fr.sf_sc.sc_ecx = rp->p_reg.cx;
64*433d6423SLionel Sambuc fr.sf_sc.sc_eax = rp->p_reg.retreg;
65*433d6423SLionel Sambuc fr.sf_sc.sc_eip = rp->p_reg.pc;
66*433d6423SLionel Sambuc fr.sf_sc.sc_cs = rp->p_reg.cs;
67*433d6423SLionel Sambuc fr.sf_sc.sc_eflags = rp->p_reg.psw;
68*433d6423SLionel Sambuc fr.sf_sc.sc_esp = rp->p_reg.sp;
69*433d6423SLionel Sambuc fr.sf_sc.sc_ss = rp->p_reg.ss;
70*433d6423SLionel Sambuc fr.sf_fp = rp->p_reg.fp;
71*433d6423SLionel Sambuc fr.sf_signum = smsg.sm_signo;
72*433d6423SLionel Sambuc new_fp = (reg_t) &frp->sf_fp;
73*433d6423SLionel Sambuc fr.sf_scpcopy = fr.sf_scp;
74*433d6423SLionel Sambuc fr.sf_ra_sigreturn = smsg.sm_sigreturn;
75*433d6423SLionel Sambuc fr.sf_ra= rp->p_reg.pc;
76*433d6423SLionel Sambuc
77*433d6423SLionel Sambuc fr.sf_sc.trap_style = rp->p_seg.p_kern_trap_style;
78*433d6423SLionel Sambuc
79*433d6423SLionel Sambuc if (fr.sf_sc.trap_style == KTS_NONE) {
80*433d6423SLionel Sambuc printf("do_sigsend: sigsend an unsaved process\n");
81*433d6423SLionel Sambuc return EINVAL;
82*433d6423SLionel Sambuc }
83*433d6423SLionel Sambuc
84*433d6423SLionel Sambuc if (proc_used_fpu(rp)) {
85*433d6423SLionel Sambuc /* save the FPU context before saving it to the sig context */
86*433d6423SLionel Sambuc save_fpu(rp);
87*433d6423SLionel Sambuc memcpy(&fr.sf_sc.sc_fpu_state, rp->p_seg.fpu_state, FPU_XFP_SIZE);
88*433d6423SLionel Sambuc }
89*433d6423SLionel Sambuc #endif
90*433d6423SLionel Sambuc
91*433d6423SLionel Sambuc #if defined(__arm__)
92*433d6423SLionel Sambuc fr.sf_sc.sc_spsr = rp->p_reg.psr;
93*433d6423SLionel Sambuc fr.sf_sc.sc_r0 = rp->p_reg.retreg;
94*433d6423SLionel Sambuc fr.sf_sc.sc_r1 = rp->p_reg.r1;
95*433d6423SLionel Sambuc fr.sf_sc.sc_r2 = rp->p_reg.r2;
96*433d6423SLionel Sambuc fr.sf_sc.sc_r3 = rp->p_reg.r3;
97*433d6423SLionel Sambuc fr.sf_sc.sc_r4 = rp->p_reg.r4;
98*433d6423SLionel Sambuc fr.sf_sc.sc_r5 = rp->p_reg.r5;
99*433d6423SLionel Sambuc fr.sf_sc.sc_r6 = rp->p_reg.r6;
100*433d6423SLionel Sambuc fr.sf_sc.sc_r7 = rp->p_reg.r7;
101*433d6423SLionel Sambuc fr.sf_sc.sc_r8 = rp->p_reg.r8;
102*433d6423SLionel Sambuc fr.sf_sc.sc_r9 = rp->p_reg.r9;
103*433d6423SLionel Sambuc fr.sf_sc.sc_r10 = rp->p_reg.r10;
104*433d6423SLionel Sambuc fr.sf_sc.sc_r11 = rp->p_reg.fp;
105*433d6423SLionel Sambuc fr.sf_sc.sc_r12 = rp->p_reg.r12;
106*433d6423SLionel Sambuc fr.sf_sc.sc_usr_sp = rp->p_reg.sp;
107*433d6423SLionel Sambuc fr.sf_sc.sc_usr_lr = rp->p_reg.lr;
108*433d6423SLionel Sambuc fr.sf_sc.sc_svc_lr = 0; /* ? */
109*433d6423SLionel Sambuc fr.sf_sc.sc_pc = rp->p_reg.pc; /* R15 */
110*433d6423SLionel Sambuc #endif
111*433d6423SLionel Sambuc
112*433d6423SLionel Sambuc /* Finish the sigcontext initialization. */
113*433d6423SLionel Sambuc fr.sf_sc.sc_mask = smsg.sm_mask;
114*433d6423SLionel Sambuc fr.sf_sc.sc_flags = rp->p_misc_flags & MF_FPU_INITIALIZED;
115*433d6423SLionel Sambuc fr.sf_sc.sc_magic = SC_MAGIC;
116*433d6423SLionel Sambuc
117*433d6423SLionel Sambuc /* Initialize the sigframe structure. */
118*433d6423SLionel Sambuc fpu_sigcontext(rp, &fr, &fr.sf_sc);
119*433d6423SLionel Sambuc
120*433d6423SLionel Sambuc /* Copy the sigframe structure to the user's stack. */
121*433d6423SLionel Sambuc if ((r = data_copy_vmcheck(caller, KERNEL, (vir_bytes)&fr,
122*433d6423SLionel Sambuc m_ptr->m_sigcalls.endpt, (vir_bytes)frp,
123*433d6423SLionel Sambuc (vir_bytes)sizeof(struct sigframe_sigcontext))) != OK)
124*433d6423SLionel Sambuc return r;
125*433d6423SLionel Sambuc
126*433d6423SLionel Sambuc /* WARNING: up to the statement above, the code may run multiple times, since
127*433d6423SLionel Sambuc * copying out the frame/context may fail with VMSUSPEND the first time. For
128*433d6423SLionel Sambuc * that reason, changes to process registers *MUST* be deferred until after
129*433d6423SLionel Sambuc * this last copy -- otherwise, these changes will be made several times,
130*433d6423SLionel Sambuc * possibly leading to corrupted process state.
131*433d6423SLionel Sambuc */
132*433d6423SLionel Sambuc
133*433d6423SLionel Sambuc /* Reset user registers to execute the signal handler. */
134*433d6423SLionel Sambuc rp->p_reg.sp = (reg_t) frp;
135*433d6423SLionel Sambuc rp->p_reg.pc = (reg_t) smsg.sm_sighandler;
136*433d6423SLionel Sambuc
137*433d6423SLionel Sambuc #if defined(__i386__)
138*433d6423SLionel Sambuc rp->p_reg.fp = new_fp;
139*433d6423SLionel Sambuc #elif defined(__arm__)
140*433d6423SLionel Sambuc /* use the ARM link register to set the return address from the signal
141*433d6423SLionel Sambuc * handler
142*433d6423SLionel Sambuc */
143*433d6423SLionel Sambuc rp->p_reg.lr = (reg_t) smsg.sm_sigreturn;
144*433d6423SLionel Sambuc if(rp->p_reg.lr & 1) { printf("sigsend: LSB LR makes no sense.\n"); }
145*433d6423SLionel Sambuc
146*433d6423SLionel Sambuc /* pass signal handler parameters in registers */
147*433d6423SLionel Sambuc rp->p_reg.retreg = (reg_t) smsg.sm_signo;
148*433d6423SLionel Sambuc rp->p_reg.r1 = 0; /* sf_code */
149*433d6423SLionel Sambuc rp->p_reg.r2 = (reg_t) fr.sf_scp;
150*433d6423SLionel Sambuc rp->p_misc_flags |= MF_CONTEXT_SET;
151*433d6423SLionel Sambuc #endif
152*433d6423SLionel Sambuc
153*433d6423SLionel Sambuc /* Signal handler should get clean FPU. */
154*433d6423SLionel Sambuc rp->p_misc_flags &= ~MF_FPU_INITIALIZED;
155*433d6423SLionel Sambuc
156*433d6423SLionel Sambuc if(!RTS_ISSET(rp, RTS_PROC_STOP)) {
157*433d6423SLionel Sambuc printf("system: warning: sigsend a running process\n");
158*433d6423SLionel Sambuc printf("caller stack: ");
159*433d6423SLionel Sambuc proc_stacktrace(caller);
160*433d6423SLionel Sambuc }
161*433d6423SLionel Sambuc
162*433d6423SLionel Sambuc return OK;
163*433d6423SLionel Sambuc }
164*433d6423SLionel Sambuc
165*433d6423SLionel Sambuc #endif /* USE_SIGSEND */
166*433d6423SLionel Sambuc
167