feat: standard vga support (mode switching, framebuffer remapping)
[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 - __builtin_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 < -1) {
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(int,
182                     sigprocmask,
183                     int,
184                     how,
185                     const sigset_t,
186                     *set,
187                     sigset_t,
188                     *oldset)
189 {
190     struct sighail* sh = &__current->sigctx;
191     *oldset = sh->sig_mask;
192
193     if (how == _SIG_BLOCK) {
194         sigset_union(sh->sig_mask, *set);
195     } else if (how == _SIG_UNBLOCK) {
196         sigset_intersect(sh->sig_mask, ~(*set));
197     } else if (how == _SIG_SETMASK) {
198         sh->sig_mask = *set;
199     } else {
200         return 0;
201     }
202
203     sigset_intersect(sh->sig_mask, ~UNMASKABLE);
204     return 1;
205 }
206
207 __DEFINE_LXSYSCALL2(int, sys_sigaction, int, signum, struct sigaction*, action)
208 {
209     if (signum <= 0 || signum >= _SIG_NUM) {
210         return -1;
211     }
212
213     if (sigset_test(UNMASKABLE, signum)) {
214         return -1;
215     }
216
217     struct sigact* sa = &__current->sigctx.signals[signum];
218
219     sa->sa_actor = (void*)action->sa_sigaction;
220     sa->sa_handler = (void*)action->sa_handler;
221     sigset_union(sa->sa_mask, sigset(signum));
222
223     return 0;
224 }
225
226 __DEFINE_LXSYSCALL(int, pause)
227 {
228     pause_current();
229     sched_yieldk();
230
231     __current->k_status = EINTR;
232     return -1;
233 }
234
235 __DEFINE_LXSYSCALL2(int, kill, pid_t, pid, int, signum)
236 {
237     return signal_send(pid, signum);
238 }
239
240 __DEFINE_LXSYSCALL1(int, sigpending, sigset_t, *sigset)
241 {
242     *sigset = __current->sigctx.sig_pending;
243     return 0;
244 }
245
246 __DEFINE_LXSYSCALL1(int, sigsuspend, sigset_t, *mask)
247 {
248     sigset_t tmp = __current->sigctx.sig_mask;
249     __current->sigctx.sig_mask = (*mask) & ~UNMASKABLE;
250
251     pause_current();
252     sched_yieldk();
253
254     __current->sigctx.sig_mask = tmp;
255     return -1;
256 }