xref: /minix3/minix/kernel/system/do_update.c (revision 01c875ce9135c75e5a6b29e7ffdbf14c2a6c5293)
1433d6423SLionel Sambuc /* The kernel call implemented in this file:
2433d6423SLionel Sambuc  *   m_type:	SYS_UPDATE
3433d6423SLionel Sambuc  *
4433d6423SLionel Sambuc  * The parameters for this kernel call are:
5433d6423SLionel Sambuc  *    m2_i1:	SYS_UPD_SRC_ENDPT 	(source process endpoint)
6433d6423SLionel Sambuc  *    m2_i2:	SYS_UPD_DST_ENDPT	(destination process endpoint)
7a1760b57SCristiano Giuffrida  *    m2_i3:	SYS_UPD_FLAGS		(update flags)
8433d6423SLionel Sambuc  */
9433d6423SLionel Sambuc 
10433d6423SLionel Sambuc #include "kernel/system.h"
11433d6423SLionel Sambuc #include "kernel/ipc.h"
12433d6423SLionel Sambuc #include <string.h>
13433d6423SLionel Sambuc #include <assert.h>
14433d6423SLionel Sambuc 
15433d6423SLionel Sambuc #if USE_UPDATE
16433d6423SLionel Sambuc 
17433d6423SLionel Sambuc #define DEBUG 0
18433d6423SLionel Sambuc 
19433d6423SLionel Sambuc #define proc_is_updatable(p) \
20433d6423SLionel Sambuc     (RTS_ISSET(p, RTS_NO_PRIV) || RTS_ISSET(p, RTS_SIG_PENDING) \
21433d6423SLionel Sambuc     || (RTS_ISSET(p, RTS_RECEIVING) && !RTS_ISSET(p, RTS_SENDING)))
22433d6423SLionel Sambuc 
2356e56d2aSCristiano Giuffrida static int inherit_priv_irq(struct proc *src_rp, struct proc *dst_rp);
2456e56d2aSCristiano Giuffrida static int inherit_priv_io(struct proc *src_rp, struct proc *dst_rp);
2556e56d2aSCristiano Giuffrida static int inherit_priv_mem(struct proc *src_rp, struct proc *dst_rp);
26062400c0SCristiano Giuffrida static void abort_proc_ipc_send(struct proc *rp);
27433d6423SLionel Sambuc static void adjust_proc_slot(struct proc *rp, struct proc *from_rp);
28433d6423SLionel Sambuc static void adjust_priv_slot(struct priv *privp, struct priv
29433d6423SLionel Sambuc 	*from_privp);
30062400c0SCristiano Giuffrida static void adjust_asyn_table(struct priv *src_privp, struct priv *dst_privp);
31433d6423SLionel Sambuc static void swap_proc_slot_pointer(struct proc **rpp, struct proc
32433d6423SLionel Sambuc 	*src_rp, struct proc *dst_rp);
33433d6423SLionel Sambuc 
34433d6423SLionel Sambuc /*===========================================================================*
35433d6423SLionel Sambuc  *				do_update				     *
36433d6423SLionel Sambuc  *===========================================================================*/
37433d6423SLionel Sambuc int do_update(struct proc * caller, message * m_ptr)
38433d6423SLionel Sambuc {
39433d6423SLionel Sambuc /* Handle sys_update(). Update a process into another by swapping their process
40433d6423SLionel Sambuc  * slots.
41433d6423SLionel Sambuc  */
42433d6423SLionel Sambuc   endpoint_t src_e, dst_e;
43062400c0SCristiano Giuffrida   int src_p, dst_p, flags;
44433d6423SLionel Sambuc   struct proc *src_rp, *dst_rp;
45433d6423SLionel Sambuc   struct priv *src_privp, *dst_privp;
46433d6423SLionel Sambuc   struct proc orig_src_proc;
47433d6423SLionel Sambuc   struct proc orig_dst_proc;
48433d6423SLionel Sambuc   struct priv orig_src_priv;
49433d6423SLionel Sambuc   struct priv orig_dst_priv;
5056e56d2aSCristiano Giuffrida   int i, r;
51433d6423SLionel Sambuc 
52433d6423SLionel Sambuc   /* Lookup slots for source and destination process. */
53062400c0SCristiano Giuffrida   flags = m_ptr->SYS_UPD_FLAGS;
54433d6423SLionel Sambuc   src_e = m_ptr->SYS_UPD_SRC_ENDPT;
55433d6423SLionel Sambuc   if(!isokendpt(src_e, &src_p)) {
56433d6423SLionel Sambuc       return EINVAL;
57433d6423SLionel Sambuc   }
58433d6423SLionel Sambuc   src_rp = proc_addr(src_p);
59433d6423SLionel Sambuc   src_privp = priv(src_rp);
60433d6423SLionel Sambuc   if(!(src_privp->s_flags & SYS_PROC)) {
61433d6423SLionel Sambuc       return EPERM;
62433d6423SLionel Sambuc   }
63433d6423SLionel Sambuc 
64433d6423SLionel Sambuc   dst_e = m_ptr->SYS_UPD_DST_ENDPT;
65433d6423SLionel Sambuc   if(!isokendpt(dst_e, &dst_p)) {
66433d6423SLionel Sambuc       return EINVAL;
67433d6423SLionel Sambuc   }
68433d6423SLionel Sambuc   dst_rp = proc_addr(dst_p);
69433d6423SLionel Sambuc   dst_privp = priv(dst_rp);
70433d6423SLionel Sambuc   if(!(dst_privp->s_flags & SYS_PROC)) {
71433d6423SLionel Sambuc       return EPERM;
72433d6423SLionel Sambuc   }
73433d6423SLionel Sambuc 
74433d6423SLionel Sambuc   assert(!proc_is_runnable(src_rp) && !proc_is_runnable(dst_rp));
75433d6423SLionel Sambuc 
76433d6423SLionel Sambuc   /* Check if processes are updatable. */
77433d6423SLionel Sambuc   if(!proc_is_updatable(src_rp) || !proc_is_updatable(dst_rp)) {
78433d6423SLionel Sambuc       return EBUSY;
79433d6423SLionel Sambuc   }
80433d6423SLionel Sambuc 
81433d6423SLionel Sambuc #if DEBUG
82433d6423SLionel Sambuc   printf("do_update: updating %d (%s, %d, %d) into %d (%s, %d, %d)\n",
83433d6423SLionel Sambuc       src_rp->p_endpoint, src_rp->p_name, src_rp->p_nr, priv(src_rp)->s_proc_nr,
84433d6423SLionel Sambuc       dst_rp->p_endpoint, dst_rp->p_name, dst_rp->p_nr, priv(dst_rp)->s_proc_nr);
85433d6423SLionel Sambuc 
86433d6423SLionel Sambuc   proc_stacktrace(src_rp);
87433d6423SLionel Sambuc   proc_stacktrace(dst_rp);
88433d6423SLionel Sambuc   printf("do_update: curr ptproc %d\n", get_cpulocal_var(ptproc)->p_endpoint);
89*01c875ceSCristiano Giuffrida   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);
90*01c875ceSCristiano Giuffrida   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);
91433d6423SLionel Sambuc #endif
92433d6423SLionel Sambuc 
9356e56d2aSCristiano Giuffrida   /* Let destination inherit allowed IRQ, I/O ranges, and memory ranges. */
9456e56d2aSCristiano Giuffrida   r = inherit_priv_irq(src_rp, dst_rp);
9556e56d2aSCristiano Giuffrida   if(r != OK) {
9656e56d2aSCristiano Giuffrida       return r;
9756e56d2aSCristiano Giuffrida   }
9856e56d2aSCristiano Giuffrida   r = inherit_priv_io(src_rp, dst_rp);
9956e56d2aSCristiano Giuffrida   if(r != OK) {
10056e56d2aSCristiano Giuffrida       return r;
10156e56d2aSCristiano Giuffrida   }
10256e56d2aSCristiano Giuffrida   r = inherit_priv_mem(src_rp, dst_rp);
10356e56d2aSCristiano Giuffrida   if(r != OK) {
10456e56d2aSCristiano Giuffrida       return r;
10556e56d2aSCristiano Giuffrida   }
10656e56d2aSCristiano Giuffrida 
107433d6423SLionel Sambuc   /* Let destination inherit the target mask from source. */
108433d6423SLionel Sambuc   for (i=0; i < NR_SYS_PROCS; i++) {
109433d6423SLionel Sambuc       if (get_sys_bit(priv(src_rp)->s_ipc_to, i)) {
110433d6423SLionel Sambuc           set_sendto_bit(dst_rp, i);
111433d6423SLionel Sambuc       }
112433d6423SLionel Sambuc   }
113433d6423SLionel Sambuc 
114433d6423SLionel Sambuc   /* Save existing data. */
115433d6423SLionel Sambuc   orig_src_proc = *src_rp;
116433d6423SLionel Sambuc   orig_src_priv = *(priv(src_rp));
117433d6423SLionel Sambuc   orig_dst_proc = *dst_rp;
118433d6423SLionel Sambuc   orig_dst_priv = *(priv(dst_rp));
119433d6423SLionel Sambuc 
120062400c0SCristiano Giuffrida   /* Adjust asyn tables. */
121062400c0SCristiano Giuffrida   adjust_asyn_table(priv(src_rp), priv(dst_rp));
122062400c0SCristiano Giuffrida   adjust_asyn_table(priv(dst_rp), priv(src_rp));
123062400c0SCristiano Giuffrida 
124062400c0SCristiano Giuffrida   /* Abort any pending send() on rollback. */
125062400c0SCristiano Giuffrida   if(flags & SYS_UPD_ROLLBACK) {
126062400c0SCristiano Giuffrida       abort_proc_ipc_send(src_rp);
127062400c0SCristiano Giuffrida   }
128062400c0SCristiano Giuffrida 
129433d6423SLionel Sambuc   /* Swap slots. */
130433d6423SLionel Sambuc   *src_rp = orig_dst_proc;
131433d6423SLionel Sambuc   *src_privp = orig_dst_priv;
132433d6423SLionel Sambuc   *dst_rp = orig_src_proc;
133433d6423SLionel Sambuc   *dst_privp = orig_src_priv;
134433d6423SLionel Sambuc 
135433d6423SLionel Sambuc   /* Adjust process slots. */
136433d6423SLionel Sambuc   adjust_proc_slot(src_rp, &orig_src_proc);
137433d6423SLionel Sambuc   adjust_proc_slot(dst_rp, &orig_dst_proc);
138433d6423SLionel Sambuc 
139433d6423SLionel Sambuc   /* Adjust privilege slots. */
140433d6423SLionel Sambuc   adjust_priv_slot(priv(src_rp), &orig_src_priv);
141433d6423SLionel Sambuc   adjust_priv_slot(priv(dst_rp), &orig_dst_priv);
142433d6423SLionel Sambuc 
143433d6423SLionel Sambuc   /* Swap global process slot addresses. */
144433d6423SLionel Sambuc   swap_proc_slot_pointer(get_cpulocal_var_ptr(ptproc), src_rp, dst_rp);
145433d6423SLionel Sambuc 
146433d6423SLionel Sambuc #if DEBUG
147433d6423SLionel Sambuc   printf("do_update: updated %d (%s, %d, %d) into %d (%s, %d, %d)\n",
148433d6423SLionel Sambuc       src_rp->p_endpoint, src_rp->p_name, src_rp->p_nr, priv(src_rp)->s_proc_nr,
149433d6423SLionel Sambuc       dst_rp->p_endpoint, dst_rp->p_name, dst_rp->p_nr, priv(dst_rp)->s_proc_nr);
150433d6423SLionel Sambuc 
151433d6423SLionel Sambuc   proc_stacktrace(src_rp);
152433d6423SLionel Sambuc   proc_stacktrace(dst_rp);
153433d6423SLionel Sambuc   printf("do_update: curr ptproc %d\n", get_cpulocal_var(ptproc)->p_endpoint);
154*01c875ceSCristiano Giuffrida   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);
155*01c875ceSCristiano Giuffrida   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);
156433d6423SLionel Sambuc #endif
157433d6423SLionel Sambuc 
158433d6423SLionel Sambuc #ifdef CONFIG_SMP
159433d6423SLionel Sambuc   bits_fill(src_rp->p_stale_tlb, CONFIG_MAX_CPUS);
160433d6423SLionel Sambuc   bits_fill(dst_rp->p_stale_tlb, CONFIG_MAX_CPUS);
161433d6423SLionel Sambuc #endif
162433d6423SLionel Sambuc 
163433d6423SLionel Sambuc   return OK;
164433d6423SLionel Sambuc }
165433d6423SLionel Sambuc 
166433d6423SLionel Sambuc /*===========================================================================*
16756e56d2aSCristiano Giuffrida  *			     inherit_priv_irq 				     *
16856e56d2aSCristiano Giuffrida  *===========================================================================*/
16956e56d2aSCristiano Giuffrida int inherit_priv_irq(struct proc *src_rp, struct proc *dst_rp)
17056e56d2aSCristiano Giuffrida {
17156e56d2aSCristiano Giuffrida   int i, r;
17256e56d2aSCristiano Giuffrida   for (i= 0; i<priv(src_rp)->s_nr_irq; i++) {
17356e56d2aSCristiano Giuffrida       r = priv_add_irq(dst_rp, priv(src_rp)->s_irq_tab[i]);
17456e56d2aSCristiano Giuffrida       if(r != OK) {
17556e56d2aSCristiano Giuffrida           return r;
17656e56d2aSCristiano Giuffrida       }
17756e56d2aSCristiano Giuffrida   }
17856e56d2aSCristiano Giuffrida 
17956e56d2aSCristiano Giuffrida   return OK;
18056e56d2aSCristiano Giuffrida }
18156e56d2aSCristiano Giuffrida 
18256e56d2aSCristiano Giuffrida /*===========================================================================*
18356e56d2aSCristiano Giuffrida  *			     inherit_priv_io 				     *
18456e56d2aSCristiano Giuffrida  *===========================================================================*/
18556e56d2aSCristiano Giuffrida  int inherit_priv_io(struct proc *src_rp, struct proc *dst_rp)
18656e56d2aSCristiano Giuffrida {
18756e56d2aSCristiano Giuffrida   int i, r;
18856e56d2aSCristiano Giuffrida   for (i= 0; i<priv(src_rp)->s_nr_io_range; i++) {
18956e56d2aSCristiano Giuffrida       r = priv_add_io(dst_rp, &(priv(src_rp)->s_io_tab[i]));
19056e56d2aSCristiano Giuffrida       if(r != OK) {
19156e56d2aSCristiano Giuffrida           return r;
19256e56d2aSCristiano Giuffrida       }
19356e56d2aSCristiano Giuffrida   }
19456e56d2aSCristiano Giuffrida 
19556e56d2aSCristiano Giuffrida   return OK;
19656e56d2aSCristiano Giuffrida }
19756e56d2aSCristiano Giuffrida 
19856e56d2aSCristiano Giuffrida /*===========================================================================*
19956e56d2aSCristiano Giuffrida  *			     inherit_priv_mem 				     *
20056e56d2aSCristiano Giuffrida  *===========================================================================*/
20156e56d2aSCristiano Giuffrida int inherit_priv_mem(struct proc *src_rp, struct proc *dst_rp)
20256e56d2aSCristiano Giuffrida {
20356e56d2aSCristiano Giuffrida   int i, r;
20456e56d2aSCristiano Giuffrida   for (i= 0; i<priv(src_rp)->s_nr_mem_range; i++) {
20556e56d2aSCristiano Giuffrida       r = priv_add_mem(dst_rp, &(priv(src_rp)->s_mem_tab[i]));
20656e56d2aSCristiano Giuffrida       if(r != OK) {
20756e56d2aSCristiano Giuffrida           return r;
20856e56d2aSCristiano Giuffrida       }
20956e56d2aSCristiano Giuffrida   }
21056e56d2aSCristiano Giuffrida 
21156e56d2aSCristiano Giuffrida   return OK;
21256e56d2aSCristiano Giuffrida }
21356e56d2aSCristiano Giuffrida 
21456e56d2aSCristiano Giuffrida /*===========================================================================*
215062400c0SCristiano Giuffrida  *			    abort_proc_ipc_send				     *
216062400c0SCristiano Giuffrida  *===========================================================================*/
217062400c0SCristiano Giuffrida void abort_proc_ipc_send(struct proc *rp)
218062400c0SCristiano Giuffrida {
219062400c0SCristiano Giuffrida   if(RTS_ISSET(rp, RTS_SENDING)) {
220062400c0SCristiano Giuffrida       struct proc **xpp;
221062400c0SCristiano Giuffrida       RTS_UNSET(rp, RTS_SENDING);
222062400c0SCristiano Giuffrida       rp->p_misc_flags &= ~MF_SENDING_FROM_KERNEL;
223062400c0SCristiano Giuffrida       xpp = &(proc_addr(_ENDPOINT_P(rp->p_sendto_e))->p_caller_q);
224062400c0SCristiano Giuffrida       while (*xpp) {
225062400c0SCristiano Giuffrida           if(*xpp == rp) {
226062400c0SCristiano Giuffrida               *xpp = rp->p_q_link;
227062400c0SCristiano Giuffrida               rp->p_q_link = NULL;
228062400c0SCristiano Giuffrida               break;
229062400c0SCristiano Giuffrida           }
230062400c0SCristiano Giuffrida           xpp = &(*xpp)->p_q_link;
231062400c0SCristiano Giuffrida       }
232062400c0SCristiano Giuffrida   }
233062400c0SCristiano Giuffrida }
234062400c0SCristiano Giuffrida 
235062400c0SCristiano Giuffrida /*===========================================================================*
236433d6423SLionel Sambuc  *			     adjust_proc_slot				     *
237433d6423SLionel Sambuc  *===========================================================================*/
238433d6423SLionel Sambuc static void adjust_proc_slot(struct proc *rp, struct proc *from_rp)
239433d6423SLionel Sambuc {
240433d6423SLionel Sambuc   /* Preserve endpoints, slot numbers, priv structure, and IPC. */
241433d6423SLionel Sambuc   rp->p_endpoint = from_rp->p_endpoint;
242433d6423SLionel Sambuc   rp->p_nr = from_rp->p_nr;
243433d6423SLionel Sambuc   rp->p_priv = from_rp->p_priv;
244433d6423SLionel Sambuc   priv(rp)->s_proc_nr = from_rp->p_nr;
245062400c0SCristiano Giuffrida 
246433d6423SLionel Sambuc   rp->p_caller_q = from_rp->p_caller_q;
247433d6423SLionel Sambuc 
248433d6423SLionel Sambuc   /* preserve scheduling */
249433d6423SLionel Sambuc   rp->p_scheduler = from_rp->p_scheduler;
250433d6423SLionel Sambuc #ifdef CONFIG_SMP
251433d6423SLionel Sambuc   rp->p_cpu = from_rp->p_cpu;
252433d6423SLionel Sambuc   memcpy(rp->p_cpu_mask, from_rp->p_cpu_mask,
253433d6423SLionel Sambuc 		  sizeof(bitchunk_t) * BITMAP_CHUNKS(CONFIG_MAX_CPUS));
254433d6423SLionel Sambuc #endif
255433d6423SLionel Sambuc }
256433d6423SLionel Sambuc 
257433d6423SLionel Sambuc /*===========================================================================*
258062400c0SCristiano Giuffrida  *			     adjust_asyn_table				     *
259062400c0SCristiano Giuffrida  *===========================================================================*/
260062400c0SCristiano Giuffrida static void adjust_asyn_table(struct priv *src_privp, struct priv *dst_privp)
261062400c0SCristiano Giuffrida {
262062400c0SCristiano Giuffrida   /* Transfer the asyn table if source's table belongs to the destination. */
263062400c0SCristiano Giuffrida   endpoint_t src_e = proc_addr(src_privp->s_proc_nr)->p_endpoint;
264062400c0SCristiano Giuffrida   endpoint_t dst_e = proc_addr(dst_privp->s_proc_nr)->p_endpoint;
265062400c0SCristiano Giuffrida 
266062400c0SCristiano Giuffrida   if(src_privp->s_asynsize > 0 && dst_privp->s_asynsize > 0 && src_privp->s_asynendpoint == dst_e) {
267062400c0SCristiano Giuffrida       if(data_copy(src_e, src_privp->s_asyntab, dst_e, dst_privp->s_asyntab,
268062400c0SCristiano Giuffrida 	  src_privp->s_asynsize*sizeof(asynmsg_t)) != OK) {
269062400c0SCristiano Giuffrida 	  printf("Warning: unable to transfer asyn table from ep %d to ep %d\n",
270062400c0SCristiano Giuffrida 	      src_e, dst_e);
271062400c0SCristiano Giuffrida       }
272062400c0SCristiano Giuffrida       else {
273062400c0SCristiano Giuffrida           dst_privp->s_asynsize = src_privp->s_asynsize;
274062400c0SCristiano Giuffrida       }
275062400c0SCristiano Giuffrida   }
276062400c0SCristiano Giuffrida }
277062400c0SCristiano Giuffrida 
278062400c0SCristiano Giuffrida /*===========================================================================*
279433d6423SLionel Sambuc  *			     adjust_priv_slot				     *
280433d6423SLionel Sambuc  *===========================================================================*/
281433d6423SLionel Sambuc static void adjust_priv_slot(struct priv *privp, struct priv *from_privp)
282433d6423SLionel Sambuc {
283433d6423SLionel Sambuc   /* Preserve privilege ids and non-privilege stuff in the priv structure. */
284433d6423SLionel Sambuc   privp->s_id = from_privp->s_id;
285433d6423SLionel Sambuc   privp->s_notify_pending = from_privp->s_notify_pending;
286433d6423SLionel Sambuc   privp->s_int_pending = from_privp->s_int_pending;
287433d6423SLionel Sambuc   privp->s_sig_pending = from_privp->s_sig_pending;
288433d6423SLionel Sambuc   privp->s_alarm_timer = from_privp->s_alarm_timer;
289433d6423SLionel Sambuc   privp->s_diag_sig = from_privp->s_diag_sig;
290433d6423SLionel Sambuc }
291433d6423SLionel Sambuc 
292433d6423SLionel Sambuc /*===========================================================================*
293433d6423SLionel Sambuc  *			   swap_proc_slot_pointer			     *
294433d6423SLionel Sambuc  *===========================================================================*/
295433d6423SLionel Sambuc static void swap_proc_slot_pointer(struct proc **rpp, struct proc *src_rp,
296433d6423SLionel Sambuc     struct proc *dst_rp)
297433d6423SLionel Sambuc {
298433d6423SLionel Sambuc   if(*rpp == src_rp) {
299433d6423SLionel Sambuc       *rpp = dst_rp;
300433d6423SLionel Sambuc   }
301433d6423SLionel Sambuc   else if(*rpp == dst_rp) {
302433d6423SLionel Sambuc       *rpp = src_rp;
303433d6423SLionel Sambuc   }
304433d6423SLionel Sambuc }
305433d6423SLionel Sambuc 
306433d6423SLionel Sambuc #endif /* USE_UPDATE */
307433d6423SLionel Sambuc 
308