xref: /minix/minix/kernel/system/do_update.c (revision 0a6a1f1d)
1 /* The kernel call implemented in this file:
2  *   m_type:	SYS_UPDATE
3  *
4  * The parameters for this kernel call are:
5  *    m2_i1:	SYS_UPD_SRC_ENDPT 	(source process endpoint)
6  *    m2_i2:	SYS_UPD_DST_ENDPT	(destination process endpoint)
7  *    m2_i3:	SYS_UPD_FLAGS		(update flags)
8  */
9 
10 #include "kernel/system.h"
11 #include "kernel/ipc.h"
12 #include <string.h>
13 #include <assert.h>
14 
15 #if USE_UPDATE
16 
17 #define DEBUG 0
18 
19 #define proc_is_updatable(p) \
20     (RTS_ISSET(p, RTS_NO_PRIV) || RTS_ISSET(p, RTS_SIG_PENDING) \
21     || (RTS_ISSET(p, RTS_RECEIVING) && !RTS_ISSET(p, RTS_SENDING)))
22 
23 static int inherit_priv_irq(struct proc *src_rp, struct proc *dst_rp);
24 static int inherit_priv_io(struct proc *src_rp, struct proc *dst_rp);
25 static int inherit_priv_mem(struct proc *src_rp, struct proc *dst_rp);
26 static void abort_proc_ipc_send(struct proc *rp);
27 static void adjust_proc_slot(struct proc *rp, struct proc *from_rp);
28 static void adjust_priv_slot(struct priv *privp, struct priv
29 	*from_privp);
30 static void adjust_asyn_table(struct priv *src_privp, struct priv *dst_privp);
31 static void swap_proc_slot_pointer(struct proc **rpp, struct proc
32 	*src_rp, struct proc *dst_rp);
33 static void swap_memreq(struct proc *src_rp, struct proc *dst_rp);
34 
35 /*===========================================================================*
36  *				do_update				     *
37  *===========================================================================*/
38 int do_update(struct proc * caller, message * m_ptr)
39 {
40 /* Handle sys_update(). Update a process into another by swapping their process
41  * slots.
42  */
43   endpoint_t src_e, dst_e;
44   int src_p, dst_p, flags;
45   struct proc *src_rp, *dst_rp;
46   struct priv *src_privp, *dst_privp;
47   struct proc orig_src_proc;
48   struct proc orig_dst_proc;
49   struct priv orig_src_priv;
50   struct priv orig_dst_priv;
51   int i, r;
52 
53   /* Lookup slots for source and destination process. */
54   flags = m_ptr->SYS_UPD_FLAGS;
55   src_e = m_ptr->SYS_UPD_SRC_ENDPT;
56   if(!isokendpt(src_e, &src_p)) {
57       return EINVAL;
58   }
59   src_rp = proc_addr(src_p);
60   src_privp = priv(src_rp);
61   if(!(src_privp->s_flags & SYS_PROC)) {
62       return EPERM;
63   }
64 
65   dst_e = m_ptr->SYS_UPD_DST_ENDPT;
66   if(!isokendpt(dst_e, &dst_p)) {
67       return EINVAL;
68   }
69   dst_rp = proc_addr(dst_p);
70   dst_privp = priv(dst_rp);
71   if(!(dst_privp->s_flags & SYS_PROC)) {
72       return EPERM;
73   }
74 
75   assert(!proc_is_runnable(src_rp) && !proc_is_runnable(dst_rp));
76 
77   /* Check if processes are updatable. */
78   if(!proc_is_updatable(src_rp) || !proc_is_updatable(dst_rp)) {
79       return EBUSY;
80   }
81 
82 #if DEBUG
83   printf("do_update: updating %d (%s, %d, %d) into %d (%s, %d, %d)\n",
84       src_rp->p_endpoint, src_rp->p_name, src_rp->p_nr, priv(src_rp)->s_proc_nr,
85       dst_rp->p_endpoint, dst_rp->p_name, dst_rp->p_nr, priv(dst_rp)->s_proc_nr);
86 
87   proc_stacktrace(src_rp);
88   proc_stacktrace(dst_rp);
89   printf("do_update: curr ptproc %d\n", get_cpulocal_var(ptproc)->p_endpoint);
90   printf("do_update: endpoint %d rts flags %x asyn tab %08x asyn endpoint %d grant tab %08x grant endpoint %d\n", src_rp->p_endpoint, src_rp->p_rts_flags, priv(src_rp)->s_asyntab, priv(src_rp)->s_asynendpoint, priv(src_rp)->s_grant_table, priv(src_rp)->s_grant_endpoint);
91   printf("do_update: endpoint %d rts flags %x asyn tab %08x asyn endpoint %d grant tab %08x grant endpoint %d\n", dst_rp->p_endpoint, dst_rp->p_rts_flags, priv(dst_rp)->s_asyntab, priv(dst_rp)->s_asynendpoint, priv(dst_rp)->s_grant_table, priv(dst_rp)->s_grant_endpoint);
92 #endif
93 
94   /* Let destination inherit allowed IRQ, I/O ranges, and memory ranges. */
95   r = inherit_priv_irq(src_rp, dst_rp);
96   if(r != OK) {
97       return r;
98   }
99   r = inherit_priv_io(src_rp, dst_rp);
100   if(r != OK) {
101       return r;
102   }
103   r = inherit_priv_mem(src_rp, dst_rp);
104   if(r != OK) {
105       return r;
106   }
107 
108   /* Let destination inherit the target mask from source. */
109   for (i=0; i < NR_SYS_PROCS; i++) {
110       if (get_sys_bit(priv(src_rp)->s_ipc_to, i)) {
111           set_sendto_bit(dst_rp, i);
112       }
113   }
114 
115   /* Save existing data. */
116   orig_src_proc = *src_rp;
117   orig_src_priv = *(priv(src_rp));
118   orig_dst_proc = *dst_rp;
119   orig_dst_priv = *(priv(dst_rp));
120 
121   /* Adjust asyn tables. */
122   adjust_asyn_table(priv(src_rp), priv(dst_rp));
123   adjust_asyn_table(priv(dst_rp), priv(src_rp));
124 
125   /* Abort any pending send() on rollback. */
126   if(flags & SYS_UPD_ROLLBACK) {
127       abort_proc_ipc_send(src_rp);
128   }
129 
130   /* Swap slots. */
131   *src_rp = orig_dst_proc;
132   *src_privp = orig_dst_priv;
133   *dst_rp = orig_src_proc;
134   *dst_privp = orig_src_priv;
135 
136   /* Adjust process slots. */
137   adjust_proc_slot(src_rp, &orig_src_proc);
138   adjust_proc_slot(dst_rp, &orig_dst_proc);
139 
140   /* Adjust privilege slots. */
141   adjust_priv_slot(priv(src_rp), &orig_src_priv);
142   adjust_priv_slot(priv(dst_rp), &orig_dst_priv);
143 
144   /* Swap global process slot addresses. */
145   swap_proc_slot_pointer(get_cpulocal_var_ptr(ptproc), src_rp, dst_rp);
146 
147   /* Swap VM request entries. */
148   swap_memreq(src_rp, dst_rp);
149 
150 #if DEBUG
151   printf("do_update: updated %d (%s, %d, %d) into %d (%s, %d, %d)\n",
152       src_rp->p_endpoint, src_rp->p_name, src_rp->p_nr, priv(src_rp)->s_proc_nr,
153       dst_rp->p_endpoint, dst_rp->p_name, dst_rp->p_nr, priv(dst_rp)->s_proc_nr);
154 
155   proc_stacktrace(src_rp);
156   proc_stacktrace(dst_rp);
157   printf("do_update: curr ptproc %d\n", get_cpulocal_var(ptproc)->p_endpoint);
158   printf("do_update: endpoint %d rts flags %x asyn tab %08x asyn endpoint %d grant tab %08x grant endpoint %d\n", src_rp->p_endpoint, src_rp->p_rts_flags, priv(src_rp)->s_asyntab, priv(src_rp)->s_asynendpoint, priv(src_rp)->s_grant_table, priv(src_rp)->s_grant_endpoint);
159   printf("do_update: endpoint %d rts flags %x asyn tab %08x asyn endpoint %d grant tab %08x grant endpoint %d\n", dst_rp->p_endpoint, dst_rp->p_rts_flags, priv(dst_rp)->s_asyntab, priv(dst_rp)->s_asynendpoint, priv(dst_rp)->s_grant_table, priv(dst_rp)->s_grant_endpoint);
160 #endif
161 
162 #ifdef CONFIG_SMP
163   bits_fill(src_rp->p_stale_tlb, CONFIG_MAX_CPUS);
164   bits_fill(dst_rp->p_stale_tlb, CONFIG_MAX_CPUS);
165 #endif
166 
167   return OK;
168 }
169 
170 /*===========================================================================*
171  *			     inherit_priv_irq 				     *
172  *===========================================================================*/
173 int inherit_priv_irq(struct proc *src_rp, struct proc *dst_rp)
174 {
175   int i, r;
176   for (i= 0; i<priv(src_rp)->s_nr_irq; i++) {
177       r = priv_add_irq(dst_rp, priv(src_rp)->s_irq_tab[i]);
178       if(r != OK) {
179           return r;
180       }
181   }
182 
183   return OK;
184 }
185 
186 /*===========================================================================*
187  *			     inherit_priv_io 				     *
188  *===========================================================================*/
189  int inherit_priv_io(struct proc *src_rp, struct proc *dst_rp)
190 {
191   int i, r;
192   for (i= 0; i<priv(src_rp)->s_nr_io_range; i++) {
193       r = priv_add_io(dst_rp, &(priv(src_rp)->s_io_tab[i]));
194       if(r != OK) {
195           return r;
196       }
197   }
198 
199   return OK;
200 }
201 
202 /*===========================================================================*
203  *			     inherit_priv_mem 				     *
204  *===========================================================================*/
205 int inherit_priv_mem(struct proc *src_rp, struct proc *dst_rp)
206 {
207   int i, r;
208   for (i= 0; i<priv(src_rp)->s_nr_mem_range; i++) {
209       r = priv_add_mem(dst_rp, &(priv(src_rp)->s_mem_tab[i]));
210       if(r != OK) {
211           return r;
212       }
213   }
214 
215   return OK;
216 }
217 
218 /*===========================================================================*
219  *			    abort_proc_ipc_send				     *
220  *===========================================================================*/
221 void abort_proc_ipc_send(struct proc *rp)
222 {
223   if(RTS_ISSET(rp, RTS_SENDING)) {
224       struct proc **xpp;
225       RTS_UNSET(rp, RTS_SENDING);
226       rp->p_misc_flags &= ~MF_SENDING_FROM_KERNEL;
227       xpp = &(proc_addr(_ENDPOINT_P(rp->p_sendto_e))->p_caller_q);
228       while (*xpp) {
229           if(*xpp == rp) {
230               *xpp = rp->p_q_link;
231               rp->p_q_link = NULL;
232               break;
233           }
234           xpp = &(*xpp)->p_q_link;
235       }
236   }
237 }
238 
239 /*===========================================================================*
240  *			     adjust_proc_slot				     *
241  *===========================================================================*/
242 static void adjust_proc_slot(struct proc *rp, struct proc *from_rp)
243 {
244   /* Preserve endpoints, slot numbers, priv structure, and IPC. */
245   rp->p_endpoint = from_rp->p_endpoint;
246   rp->p_nr = from_rp->p_nr;
247   rp->p_priv = from_rp->p_priv;
248   priv(rp)->s_proc_nr = from_rp->p_nr;
249 
250   rp->p_caller_q = from_rp->p_caller_q;
251 
252   /* preserve scheduling */
253   rp->p_scheduler = from_rp->p_scheduler;
254 #ifdef CONFIG_SMP
255   rp->p_cpu = from_rp->p_cpu;
256   memcpy(rp->p_cpu_mask, from_rp->p_cpu_mask,
257 		  sizeof(bitchunk_t) * BITMAP_CHUNKS(CONFIG_MAX_CPUS));
258 #endif
259 }
260 
261 /*===========================================================================*
262  *			     adjust_asyn_table				     *
263  *===========================================================================*/
264 static void adjust_asyn_table(struct priv *src_privp, struct priv *dst_privp)
265 {
266   /* Transfer the asyn table if source's table belongs to the destination. */
267   endpoint_t src_e = proc_addr(src_privp->s_proc_nr)->p_endpoint;
268   endpoint_t dst_e = proc_addr(dst_privp->s_proc_nr)->p_endpoint;
269 
270   if(src_privp->s_asynsize > 0 && dst_privp->s_asynsize > 0 && src_privp->s_asynendpoint == dst_e) {
271       if(data_copy(src_e, src_privp->s_asyntab, dst_e, dst_privp->s_asyntab,
272 	  src_privp->s_asynsize*sizeof(asynmsg_t)) != OK) {
273 	  printf("Warning: unable to transfer asyn table from ep %d to ep %d\n",
274 	      src_e, dst_e);
275       }
276       else {
277           dst_privp->s_asynsize = src_privp->s_asynsize;
278       }
279   }
280 }
281 
282 /*===========================================================================*
283  *			     adjust_priv_slot				     *
284  *===========================================================================*/
285 static void adjust_priv_slot(struct priv *privp, struct priv *from_privp)
286 {
287   /* Preserve privilege ids and non-privilege stuff in the priv structure. */
288   privp->s_id = from_privp->s_id;
289   privp->s_asyn_pending = from_privp->s_asyn_pending;
290   privp->s_notify_pending = from_privp->s_notify_pending;
291   privp->s_int_pending = from_privp->s_int_pending;
292   privp->s_sig_pending = from_privp->s_sig_pending;
293   privp->s_alarm_timer = from_privp->s_alarm_timer;
294   privp->s_diag_sig = from_privp->s_diag_sig;
295 }
296 
297 /*===========================================================================*
298  *			   swap_proc_slot_pointer			     *
299  *===========================================================================*/
300 static void swap_proc_slot_pointer(struct proc **rpp, struct proc *src_rp,
301     struct proc *dst_rp)
302 {
303   if(*rpp == src_rp) {
304       *rpp = dst_rp;
305   }
306   else if(*rpp == dst_rp) {
307       *rpp = src_rp;
308   }
309 }
310 
311 /*===========================================================================*
312  *				swap_memreq				     *
313  *===========================================================================*/
314 static void swap_memreq(struct proc *src_rp, struct proc *dst_rp)
315 {
316 /* If either the source or the destination process is part of the VM request
317  * chain, but not both, then swap the process pointers in the chain.
318  */
319   struct proc **rpp;
320 
321   if (RTS_ISSET(src_rp, RTS_VMREQUEST) == RTS_ISSET(dst_rp, RTS_VMREQUEST))
322 	return; /* nothing to do */
323 
324   for (rpp = &vmrequest; *rpp != NULL;
325      rpp = &(*rpp)->p_vmrequest.nextrequestor) {
326 	if (*rpp == src_rp) {
327 		dst_rp->p_vmrequest.nextrequestor =
328 		    src_rp->p_vmrequest.nextrequestor;
329 		*rpp = dst_rp;
330 		break;
331 	} else if (*rpp == dst_rp) {
332 		src_rp->p_vmrequest.nextrequestor =
333 		    dst_rp->p_vmrequest.nextrequestor;
334 		*rpp = src_rp;
335 		break;
336 	}
337   }
338 }
339 
340 #endif /* USE_UPDATE */
341 
342