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