minix/kernel/system/do_update.c
Tomas Hruby 8fa95abae4 SMP - fixed usage of stale TLB entries
- when kernel copies from userspace, it must be sure that the TLB
  entries are not stale and thus the referenced memory is correct

- everytime we change a process' address space we set p_stale_tlb
  bits for all CPUs.

- Whenever a cpu finds its bit set when it wants to access the
  process' memory, it refreshes the TLB

- it is more conservative than it needs to be but it has low
  overhead than checking precisely
2012-01-13 11:30:00 +00:00

187 lines
5.6 KiB
C

/* The kernel call implemented in this file:
* m_type: SYS_UPDATE
*
* The parameters for this kernel call are:
* m2_i1: SYS_UPD_SRC_ENDPT (source process endpoint)
* m2_i2: SYS_UPD_DST_ENDPT (destination process endpoint)
*/
#include "kernel/system.h"
#include "kernel/ipc.h"
#include <string.h>
#include <assert.h>
#if USE_UPDATE
#define DEBUG 0
#define proc_is_updatable(p) \
(RTS_ISSET(p, RTS_NO_PRIV) || RTS_ISSET(p, RTS_SIG_PENDING) \
|| (RTS_ISSET(p, RTS_RECEIVING) && !RTS_ISSET(p, RTS_SENDING)))
FORWARD _PROTOTYPE(void adjust_proc_slot, (struct proc *rp,
struct proc *from_rp));
FORWARD _PROTOTYPE(void adjust_priv_slot, (struct priv *privp,
struct priv *from_privp));
FORWARD _PROTOTYPE(void swap_proc_slot_pointer, (struct proc **rpp,
struct proc *src_rp, struct proc *dst_rp));
/*===========================================================================*
* do_update *
*===========================================================================*/
PUBLIC int do_update(struct proc * caller, message * m_ptr)
{
/* Handle sys_update(). Update a process into another by swapping their process
* slots.
*/
endpoint_t src_e, dst_e;
int src_p, dst_p;
struct proc *src_rp, *dst_rp;
struct priv *src_privp, *dst_privp;
struct proc orig_src_proc;
struct proc orig_dst_proc;
struct priv orig_src_priv;
struct priv orig_dst_priv;
int i;
/* Lookup slots for source and destination process. */
src_e = m_ptr->SYS_UPD_SRC_ENDPT;
if(!isokendpt(src_e, &src_p)) {
return EINVAL;
}
src_rp = proc_addr(src_p);
src_privp = priv(src_rp);
if(!(src_privp->s_flags & SYS_PROC)) {
return EPERM;
}
dst_e = m_ptr->SYS_UPD_DST_ENDPT;
if(!isokendpt(dst_e, &dst_p)) {
return EINVAL;
}
dst_rp = proc_addr(dst_p);
dst_privp = priv(dst_rp);
if(!(dst_privp->s_flags & SYS_PROC)) {
return EPERM;
}
assert(!proc_is_runnable(src_rp) && !proc_is_runnable(dst_rp));
/* Check if processes are updatable. */
if(!proc_is_updatable(src_rp) || !proc_is_updatable(dst_rp)) {
return EBUSY;
}
#if DEBUG
printf("do_update: updating %d (%s, %d, %d) into %d (%s, %d, %d)\n",
src_rp->p_endpoint, src_rp->p_name, src_rp->p_nr, priv(src_rp)->s_proc_nr,
dst_rp->p_endpoint, dst_rp->p_name, dst_rp->p_nr, priv(dst_rp)->s_proc_nr);
proc_stacktrace(src_rp);
proc_stacktrace(dst_rp);
printf("do_update: curr ptproc %d\n", get_cpulocal_var(ptproc)->p_endpoint);
#endif
/* Let destination inherit the target mask from source. */
for (i=0; i < NR_SYS_PROCS; i++) {
if (get_sys_bit(priv(src_rp)->s_ipc_to, i)) {
set_sendto_bit(dst_rp, i);
}
}
/* Save existing data. */
orig_src_proc = *src_rp;
orig_src_priv = *(priv(src_rp));
orig_dst_proc = *dst_rp;
orig_dst_priv = *(priv(dst_rp));
/* Swap slots. */
*src_rp = orig_dst_proc;
*src_privp = orig_dst_priv;
*dst_rp = orig_src_proc;
*dst_privp = orig_src_priv;
/* Adjust process slots. */
adjust_proc_slot(src_rp, &orig_src_proc);
adjust_proc_slot(dst_rp, &orig_dst_proc);
/* Adjust privilege slots. */
adjust_priv_slot(priv(src_rp), &orig_src_priv);
adjust_priv_slot(priv(dst_rp), &orig_dst_priv);
/* Swap global process slot addresses. */
swap_proc_slot_pointer(get_cpulocal_var_ptr(ptproc), src_rp, dst_rp);
/* Fix segments. */
alloc_segments(src_rp);
alloc_segments(dst_rp);
prot_init();
#if DEBUG
printf("do_update: updated %d (%s, %d, %d) into %d (%s, %d, %d)\n",
src_rp->p_endpoint, src_rp->p_name, src_rp->p_nr, priv(src_rp)->s_proc_nr,
dst_rp->p_endpoint, dst_rp->p_name, dst_rp->p_nr, priv(dst_rp)->s_proc_nr);
proc_stacktrace(src_rp);
proc_stacktrace(dst_rp);
printf("do_update: curr ptproc %d\n", get_cpulocal_var(ptproc)->p_endpoint);
#endif
#ifdef CONFIG_SMP
bits_fill(src_rp->p_stale_tlb, CONFIG_MAX_CPUS);
bits_fill(dst_rp->p_stale_tlb, CONFIG_MAX_CPUS);
#endif
return OK;
}
/*===========================================================================*
* adjust_proc_slot *
*===========================================================================*/
PRIVATE void adjust_proc_slot(struct proc *rp, struct proc *from_rp)
{
/* Preserve endpoints, slot numbers, priv structure, and IPC. */
rp->p_endpoint = from_rp->p_endpoint;
rp->p_nr = from_rp->p_nr;
rp->p_priv = from_rp->p_priv;
priv(rp)->s_proc_nr = from_rp->p_nr;
rp->p_caller_q = from_rp->p_caller_q;
/* preserve scheduling */
rp->p_scheduler = from_rp->p_scheduler;
#ifdef CONFIG_SMP
rp->p_cpu = from_rp->p_cpu;
memcpy(rp->p_cpu_mask, from_rp->p_cpu_mask,
sizeof(bitchunk_t) * BITMAP_CHUNKS(CONFIG_MAX_CPUS));
#endif
}
/*===========================================================================*
* adjust_priv_slot *
*===========================================================================*/
PRIVATE void adjust_priv_slot(struct priv *privp, struct priv *from_privp)
{
/* Preserve privilege ids and non-privilege stuff in the priv structure. */
privp->s_id = from_privp->s_id;
privp->s_notify_pending = from_privp->s_notify_pending;
privp->s_int_pending = from_privp->s_int_pending;
privp->s_sig_pending = from_privp->s_sig_pending;
privp->s_alarm_timer = from_privp->s_alarm_timer;
}
/*===========================================================================*
* swap_proc_slot_pointer *
*===========================================================================*/
PRIVATE void swap_proc_slot_pointer(struct proc **rpp, struct proc *src_rp,
struct proc *dst_rp)
{
if(*rpp == src_rp) {
*rpp = dst_rp;
}
else if(*rpp == dst_rp) {
*rpp = src_rp;
}
}
#endif /* USE_UPDATE */