feat: a better boot command line parser
[lunaix-os.git] / lunaix-os / kernel / process / signal.c
1 #include <lunaix/process.h>
2 #include <lunaix/sched.h>
3 #include <lunaix/signal.h>
4 #include <lunaix/spike.h>
5 #include <lunaix/status.h>
6 #include <lunaix/syscall.h>
7 #include <lunaix/syslog.h>
8
9 #include <klibc/string.h>
10
11 #include <sys/mm/mempart.h>
12
13 LOG_MODULE("SIG")
14
15 extern struct scheduler sched_ctx; /* kernel/sched.c */
16
17 #define UNMASKABLE (sigset(SIGKILL) | sigset(SIGTERM))
18 #define TERMSIG (sigset(SIGSEGV) | sigset(SIGINT) | UNMASKABLE)
19 #define CORE (sigset(SIGSEGV))
20 #define within_kstack(addr)                                                    \
21     (KERNEL_STACK <= (addr) && (addr) <= KERNEL_STACK_END)
22
23 static inline void
24 signal_terminate(int errcode)
25 {
26     terminate_proc(errcode | PEXITSIG);
27 }
28
29 // Referenced in kernel/asm/x86/interrupt.S
30 void*
31 signal_dispatch()
32 {
33     if (!__current->sigctx.sig_pending) {
34         // 没有待处理信号
35         return 0;
36     }
37
38     struct sighail* psig = &__current->sigctx;
39     struct sigact* prev_working = psig->inprogress;
40     sigset_t mask = psig->sig_mask | (prev_working ? prev_working->sa_mask : 0);
41
42     int sig_selected = 31 - clz(psig->sig_pending & ~mask);
43
44     sigset_clear(psig->sig_pending, sig_selected);
45
46     struct sigact* action = &psig->signals[sig_selected];
47
48     if (sig_selected == 0) {
49         // SIG0 is reserved
50         return 0;
51     }
52
53     if (!action->sa_actor) {
54         if (sigset_test(TERMSIG, sig_selected)) {
55             signal_terminate(sig_selected);
56             schedule();
57             // never return
58         }
59         return 0;
60     }
61
62     ptr_t ustack = __current->ustack_top;
63
64     if ((int)(ustack - USR_STACK) < (int)sizeof(struct proc_sig)) {
65         // 用户栈没有空间存放信号上下文
66         return 0;
67     }
68
69     struct proc_sig* sigframe =
70         (struct proc_sig*)((ustack - sizeof(struct proc_sig)) & ~0xf);
71
72     sigframe->sig_num = sig_selected;
73     sigframe->sigact = action->sa_actor;
74     sigframe->sighand = action->sa_handler;
75
76     sigframe->saved_ictx = __current->intr_ctx;
77
78     action->prev = prev_working;
79     psig->inprogress = action;
80
81     return sigframe;
82 }
83
84 void
85 proc_clear_signal(struct proc_info* proc)
86 {
87     memset(&proc->sigctx, 0, sizeof(proc->sigctx));
88 }
89
90 void
91 proc_setsignal(struct proc_info* proc, int signum)
92 {
93     sigset_add(proc->sigctx.sig_pending, signum);
94     proc->sigctx.signals[signum].sender = __current->pid;
95 }
96
97 int
98 signal_send(pid_t pid, int signum)
99 {
100     if (signum < 0 || signum >= _SIG_NUM) {
101         __current->k_status = EINVAL;
102         return -1;
103     }
104
105     pid_t sender_pid = __current->pid;
106     struct proc_info* proc;
107
108     if (pid > 0) {
109         proc = get_process(pid);
110         goto send_single;
111     } else if (!pid) {
112         proc = __current;
113         goto send_grp;
114     } else if (pid < 0) {
115         proc = get_process(-pid);
116         goto send_grp;
117     } else {
118         // TODO: send to all process.
119         //  But I don't want to support it yet.
120         __current->k_status = EINVAL;
121         return -1;
122     }
123
124 send_grp:
125     struct proc_info *pos, *n;
126     llist_for_each(pos, n, &proc->grp_member, grp_member)
127     {
128         struct sighail* sh = &pos->sigctx;
129         sigset_add(sh->sig_pending, signum);
130         sh->signals[signum].sender = sender_pid;
131     }
132
133 send_single:
134     if (proc_terminated(proc)) {
135         __current->k_status = EINVAL;
136         return -1;
137     }
138
139     sigset_add(proc->sigctx.sig_pending, signum);
140     proc->sigctx.signals[signum].sender = sender_pid;
141
142     return 0;
143 }
144
145 __DEFINE_LXSYSCALL1(int, sigreturn, struct proc_sig, *sig_ctx)
146 {
147     __current->intr_ctx = sig_ctx->saved_ictx;
148
149     struct sigact* current = __current->sigctx.inprogress;
150     if (current) {
151         __current->sigctx.inprogress = current->prev;
152         current->prev = NULL;
153     } else {
154         __current->sigctx.inprogress = NULL;
155     }
156
157     if (proc_terminated(__current)) {
158         __current->exit_code |= PEXITSIG;
159     } else if (sigset_test(CORE, sig_ctx->sig_num)) {
160         signal_terminate(sig_ctx->sig_num);
161     }
162
163     ptr_t ictx = (ptr_t)__current->intr_ctx;
164
165     /*
166         Ensure our restored context is within kernel stack
167
168         This prevent user to forge their own context such that arbitrary code
169        can be executed as supervisor level
170     */
171     if (!within_kstack(ictx)) {
172         signal_terminate(SIGSEGV);
173     }
174
175     schedule();
176
177     // never reach!
178     return 0;
179 }
180
181 __DEFINE_LXSYSCALL3(
182     int, sigprocmask, int, how, const sigset_t, *set, sigset_t, *oldset)
183 {
184     struct sighail* sh = &__current->sigctx;
185     *oldset = sh->sig_mask;
186
187     if (how == _SIG_BLOCK) {
188         sigset_union(sh->sig_mask, *set);
189     } else if (how == _SIG_UNBLOCK) {
190         sigset_intersect(sh->sig_mask, ~(*set));
191     } else if (how == _SIG_SETMASK) {
192         sh->sig_mask = *set;
193     } else {
194         return 0;
195     }
196
197     sigset_intersect(sh->sig_mask, ~UNMASKABLE);
198     return 1;
199 }
200
201 __DEFINE_LXSYSCALL2(int, sys_sigaction, int, signum, struct sigaction*, action)
202 {
203     if (signum <= 0 || signum >= _SIG_NUM) {
204         return -1;
205     }
206
207     if (sigset_test(UNMASKABLE, signum)) {
208         return -1;
209     }
210
211     struct sigact* sa = &__current->sigctx.signals[signum];
212
213     sa->sa_actor = (void*)action->sa_sigaction;
214     sa->sa_handler = (void*)action->sa_handler;
215     sigset_union(sa->sa_mask, sigset(signum));
216
217     return 0;
218 }
219
220 __DEFINE_LXSYSCALL(int, pause)
221 {
222     pause_current();
223     sched_yieldk();
224
225     __current->k_status = EINTR;
226     return -1;
227 }
228
229 __DEFINE_LXSYSCALL2(int, kill, pid_t, pid, int, signum)
230 {
231     return signal_send(pid, signum);
232 }
233
234 __DEFINE_LXSYSCALL1(int, sigpending, sigset_t, *sigset)
235 {
236     *sigset = __current->sigctx.sig_pending;
237     return 0;
238 }
239
240 __DEFINE_LXSYSCALL1(int, sigsuspend, sigset_t, *mask)
241 {
242     sigset_t tmp = __current->sigctx.sig_mask;
243     __current->sigctx.sig_mask = (*mask) & ~UNMASKABLE;
244
245     pause_current();
246     sched_yieldk();
247
248     __current->sigctx.sig_mask = tmp;
249     return -1;
250 }