comment 'openMosix'
bool 'openMosix process migration support' CONFIG_MOSIX
if [ "$CONFIG_MOSIX" = "y" ]; then
bool 'Support clusters with a complex network topology' CONFIG_MOSIX_TOPOLOGY
if [ "$CONFIG_MOSIX_TOPOLOGY" = "y" ]; then
int 'Maximum network-topology complexity to support (2-10)' CONFIG_MOSIX_MAXTOPOLOGY 4
fi
bool 'Stricter security on openMosix ports' CONFIG_MOSIX_SECUREPORTS
int 'Level of process-identity disclosure (0-3)' CONFIG_MOSIX_DISCLOSURE 1
#bool 'Create the kernel with a "-openmosix" extension' CONFIG_MOSIX_EXTMOSIX
bool 'openMosix File-System' CONFIG_MOSIX_FS
if [ "$CONFIG_MOSIX_FS" = "y" ]; then
define_bool CONFIG_MOSIX_DFSA y
fi
bool 'Poll/Select exceptions on pipes' CONFIG_MOSIX_PIPE_EXCEPTIONS
bool 'Disable OOM Killer' CONFIG_openMosix_NO_OOM
bool 'Load Limit' CONFIG_MOSIX_LOADLIMIT
fi
endmenu
#ifdef CONFIG_MOSIX #include "mosasm.H" /* libreria de codigo ensamblador de openMosix */ #endif /* CONFIG_MOSIX */Para pasar de modo sistema a modo usuario:
ENTRY(system_call)
pushl %eax # save orig_eax
SAVE_ALL
GET_CURRENT(%ebx)
testb $0x02,tsk_ptrace(%ebx) # PT_TRACESYS
jne tracesys
cmpl $(NR_syscalls),%eax
jae badsys
#ifdef CONFIG_MOSIX
testl $(DTRACESYS1|DTRACESYS2),DFLAGS(%ebx)
jne adjust_trace_before_syscall
adjusted_trace:
testb $DREMOTE,DFLAGS(%ebx)
je local_syscall
on_remote:
pushl %eax
call *SYMBOL_NAME(remote_sys_call_table)(,%eax,4)
addl $4,%esp
movl %eax,EAX(%esp)
jmp ret_from_sys_call
local_syscall:
#endif /* CONFIG_MOSIX */
call *SYMBOL_NAME(sys_call_table)(,%eax,4)
movl %eax,EAX(%esp) # save the return value
#ifdef CONFIG_MOSIX
call SYMBOL_NAME(mosix_local_syscall)
#endif /* CONFIG_MOSIX */
ENTRY(ret_from_sys_call)
#ifdef CONFIG_MOSIX
testl $(DTRACESYS1|DTRACESYS2),DFLAGS(%ebx)
jne adjust_trace_before_syscall
ret_check_reschedule:
#endif /* CONFIG_MOSIX */
cli # need_resched and signals atomic test
cmpl $0,need_resched(%ebx)
jne reschedule
cmpl $0,sigpending(%ebx)
jne signal_return
#ifdef CONFIG_MOSIX
straight_to_mosix:
call SYMBOL_NAME(mosix_pre_usermode_actions)
testl %eax,%eax
jne ret_from_sys_call
#endif /* CONFIG_MOSIX */
restore_all:
RESTORE_ALL
ALIGN
signal_return:
sti # we can get here from an interrupt handler
testl $(VM_MASK),EFLAGS(%esp)
movl %esp,%eax
jne v86_signal_return
xorl %edx,%edx
call SYMBOL_NAME(do_signal)
#ifdef CONFIG_MOSIX
jmp straight_to_mosix
#else
jmp restore_all
#endif /* CONFIG_MOSIX */
ALIGN
v86_signal_return:
call SYMBOL_NAME(save_v86_state)
movl %eax,%esp
xorl %edx,%edx
call SYMBOL_NAME(do_signal)
#ifdef CONFIG_MOSIX
jmp straight_to_mosix
#else
jmp restore_all
#endif /* CONFIG_MOSIX */
ALIGN
tracesys:
movl $-ENOSYS,EAX(%esp)
call SYMBOL_NAME(syscall_trace)
#ifdef CONFIG_MOSIX
adjust_trace_before_syscall: # only arrive here with DTRACESYS(1|2)
testl $DDEPUTY,DFLAGS(%ebx)
jne straight_to_mosix # no mess with signals/syscalls/tracesys
testl $DREMOTE,DFLAGS(%ebx)
je no_need_to_unsync
call wait_for_permission_to_continue
no_need_to_unsync:
testl $DTRACESYS2,DFLAGS(%ebx)
jne second_tracesys # skipping system-call
orl $DTRACESYS2,DFLAGS(%ebx) # next time we skip the system-call
movl $-ENOSYS,EAX(%esp)
movl ORIG_EAX(%esp),%eax
cmpl $(NR_syscalls),%eax
jae second_tracesys # prevent system-call out of range trick
jmp adjusted_trace # now do the system-call
second_tracesys: # note: "syscall_trace" clears the flags
#else
movl ORIG_EAX(%esp),%eax
cmpl $(NR_syscalls),%eax
jae tracesys_exit
call *SYMBOL_NAME(sys_call_table)(,%eax,4)
movl %eax,EAX(%esp) # save the return value
tracesys_exit:
#endif /* CONFIG_MOSIX */
call SYMBOL_NAME(syscall_trace)
jmp ret_from_sys_call
badsys:
movl $-ENOSYS,EAX(%esp)
jmp ret_from_sys_call
ALIGN
ENTRY(ret_from_intr)
GET_CURRENT(%ebx)
ret_from_exception:
movl EFLAGS(%esp),%eax # mix EFLAGS and CS
movb CS(%esp),%al
testl $(VM_MASK | 3),%eax # return to VM86 mode or non-supervisor?
#ifdef CONFIG_MOSIX
jne ret_check_reschedule
#else
jne ret_from_sys_call
#endif /* CONFIG_MOSIX */
jmp restore_all
ALIGN
reschedule:
call SYMBOL_NAME(schedule) # test
jmp ret_from_sys_call
static void set_bitmap()
Configura la máscara de permisos, esto no difiere del codigo del kernel vanilla de Linux.
Al mapa bitmap se guarda el valor turn_on.
static void set_bitmap(unsigned long *bitmap, short base, short extent, int new_value)
{
int mask;
unsigned long *bitmap_base = bitmap + (base >> 5);
unsigned short low_index = base & 0x1f;
int length = low_index + extent;
if (low_index != 0) {
mask = (~0 << low_index);
if (length < 32)
mask &= ~(~0 << length);
if (new_value)
*bitmap_base++ |= mask;
else
*bitmap_base++ &= ~mask;
length -= 32;
}
mask = (new_value ? ~0 : 0);
while (length >= 32) {
*bitmap_base++ = mask;
length -= 32;
}
if (length > 0) {
mask = ~(~0 << length);
if (new_value)
*bitmap_base++ |= mask;
else
*bitmap_base++ &= ~mask;
}
}
asmlinkage int sys_ioperm()
Esta función modifica los permisos de E/S para el proceso en curso.
Se invocará cuando un proceso deba dejar de mapear memoria del dispositivo
de E/S o, en el caso de openMosix, cuando un proceso migrado quiera acceder a
un dispositivo que se encuentre local al UHN.
asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
{
struct thread_struct * t = ¤t->thread; /*proceso en curso */
struct tss_struct * tss = init_tss + smp_processor_id();
if ((from + num <= from) || (from + num > IO_BITMAP_SIZE*32))
return -EINVAL;
if (turn_on && !capable(CAP_SYS_RAWIO))
return -EPERM;
#ifdef CONFIG_MOSIX /* si openmosix debe devolver el */
if(turn_on && !mosix_go_home_for_reason(1, DSTAY_FOR_IOPL))
return(-ENOMEM); /* proceso a su UHN por razones de E/S */
#endif /* CONFIG_MOSIX */
/* Si el proceso aun no habia invocado a ioperm() se carga el mapa en memoria */
if (!t->ioperm) {
memset(t->io_bitmap,0xff,(IO_BITMAP_SIZE+1)*4);
t->ioperm = 1;
}
/* se deberan copiar las modificaciones a los threads y TSS */
/* TSS -Task State Segment. Es un segmento especifico en arquitecturas
x86 para guardar contextos hardware */
set_bitmap(t->io_bitmap, from, num, !turn_on);
if (tss->bitmap == IO_BITMAP_OFFSET) {
set_bitmap(tss->io_bitmap, from, num, !turn_on);
} else {
memcpy(tss->io_bitmap, t->io_bitmap, IO_BITMAP_BYTES);
tss->bitmap = IO_BITMAP_OFFSET; /* Activa el mapa modificado en el TSS */
}
return 0;
}
int copy_siginfo_to_user()
Para que el área de usuario esté informado del estado de los señales,
controlado por el área de kernel, se le debe pasar la información sobre el
mapa de interrupciones.
En procesos migrados esto es importante, puesto que supone una comunicación entre remote y deputy.
int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
{
if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
return -EFAULT;
if (from->si_code < 0)
return __copy_to_user(to, from, sizeof(siginfo_t));
else {
#ifdef CONFIG_MOSIX
int sz = offsetof(struct siginfo, _sifields);
switch(from->si_code >> 16)
{
case __SI_FAULT >> 16:
sz += sizeof(to->_sifields._sigfault);
break;
case __SI_CHLD >> 16:
sz += sizeof(to->_sifields._sigchld);
break;
case __SI_MIGRATION >> 16:
sz += sizeof(to->_sifields._sigmig);
break;
default:
sz += sizeof(to->_sifields._kill);
break;
}
return(__copy_to_user(to, from, sz));
#else
int err;
err = __put_user(from->si_signo, &to->si_signo);
err |= __put_user(from->si_errno, &to->si_errno);
err |= __put_user((short)from->si_code, &to->si_code);
/* First 32bits of unions are always present. */
err |= __put_user(from->si_pid, &to->si_pid);
switch (from->si_code >> 16) {
case __SI_FAULT >> 16:
break;
case __SI_CHLD >> 16:
err |= __put_user(from->si_utime, &to->si_utime);
err |= __put_user(from->si_stime, &to->si_stime);
err |= __put_user(from->si_status, &to->si_status);
default:
err |= __put_user(from->si_uid, &to->si_uid);
break;
}
return err;
#endif /* CONFIG_MOSIX */
}
}
asmlinkage int sys_sigreturn()
Envía el señal para mandar de regreso el remote.
asmlinkage int sys_sigreturn(unsigned long __unused)
{
struct pt_regs *regs = (struct pt_regs *) &__unused;
#ifdef CONFIG_MOSIX
struct sigframe *frame;
#else
struct sigframe *frame = (struct sigframe *)(regs->esp - 8);
#endif /* CONFIG_MOSIX */
sigset_t set;
int eax;
#ifdef CONFIG_MOSIX
mosix_obtain_registers(BIT_OF_REGISTER(esp));
frame = (struct sigframe *)(regs->esp - 8);
#endif /* CONFIG_MOSIX */
La estructura sigframe contiene:
char *pretcode;
int sig;
struct sigcontext sc;
struct _fpstate fpstate;
unsigned long extramask[_NSIG_WORDS-1];
char retcode[8];
if (verify_area(VERIFY_READ, frame, sizeof(*frame))) /* verifica la correcta lectura al remoto */
goto badframe;
if (__get_user(set.sig[0], &frame->sc.oldmask)
|| (_NSIG_WORDS > 1
&& __copy_from_user(&set.sig[1], &frame->extramask,
sizeof(frame->extramask))))
/* con una correcta comunicacion, copia desde el remoto al UHN */
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(¤t->sigmask_lock); /* bloquea la seccion critica con semaforos */
current->blocked = set; /* aplica la mascara de los registros al proceso en curso */
/* los registros bloquean el proceso, para recibir el senal */
recalc_sigpending(current); /* desbloquea la proteccion */
spin_unlock_irq(¤t->sigmask_lock);
#ifdef CONFIG_MOSIX
if(current->mosix.dflags & DDEPUTY)
{
if (mosix_deputy_restore_sigcontext(&frame->sc, &eax))
/* restaura el contexto de los registros en el deputy */
goto badframe;
} /* si no se recupera bien el registro eax */
else
#endif /* CONFIG_MOSIX */
if (restore_sigcontext(regs, &frame->sc, &eax))
goto badframe;
return eax;
badframe:
force_sig(SIGSEGV, current);
/* en caso de que no se proceda satisfactoriamente, se envia SIGSEGV para abortar*/
return 0;
}
asmlinkage int handle_signal()
Esta rutina atiende a las señales que recibe un proceso.
static void
handle_signal(unsigned long sig, struct k_sigaction *ka,
siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
{
#ifdef CONFIG_MOSIX
mosix_obtain_registers(
BIT_OF_REGISTER(orig_eax)|BIT_OF_REGISTER(eax)|BIT_OF_REGISTER(eip));
#endif /* CONFIG_MOSIX */
/* si se esta ejecutando una llamada a sistema, como es una se~nal */
if (regs->orig_eax >= 0) {
/* en este caso se informa al proceso, a traves del registro eax */
switch (regs->eax) {
case -ERESTARTNOHAND:
regs->eax = -EINTR;
break;
case -ERESTARTSYS:
if (!(ka->sa.sa_flags & SA_RESTART)) {
regs->eax = -EINTR;
break;
}
/* fallthrough */
case -ERESTARTNOINTR:
regs->eax = regs->orig_eax;
regs->eip -= 2;
}
}
/* Set up the stack frame */
#ifdef CONFIG_MOSIX
/* si el proceso no es un proceso Linux completo, sino un deputy, se lo
trata como debe hacerse, mediante una llamada a mosix_deputy_setup_frame().
La mayor diferencia es que el deputy carece de segmento de datos para
almacenar esta informacion*/
if(current->mosix.dflags & DDEPUTY)
mosix_deputy_setup_frame(sig, ka, *info, oldset);
else
#endif /* CONFIG_MOSIX */
if (ka->sa.sa_flags & SA_SIGINFO)
setup_rt_frame(sig, ka, info, oldset, regs);
else
setup_frame(sig, ka, oldset, regs);
if (ka->sa.sa_flags & SA_ONESHOT)
ka->sa.sa_handler = SIG_DFL;
if (!(ka->sa.sa_flags & SA_NODEFER)) {
spin_lock_irq(¤t->sigmask_lock); /* se bloquea la recepcion de interrupciones para el proceso */
sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
sigaddset(¤t->blocked,sig); /* se actualiza el estado de las interrupciones del proceso */
recalc_sigpending(current); /* se atiende a las interrupciones pendientes */
spin_unlock_irq(¤t->sigmask_lock); /* se desbloquea */
}
}
asmlinkage int save_v86_state()
Guarda el estado del proceso en emulación. Se le indica la opción de
bloqueo para que PPM no intente migrarlo.
struct pt_regs * save_v86_state(struct kernel_vm86_regs * regs)
{
struct tss_struct *tss;
struct pt_regs *ret;
unsigned long tmp;
#ifdef CONFIG_MOSIX
if(current->mosix.dflags & DREMOTE)
panic("remote save_v86");
#endif /* CONFIG_MOSIX */
if (!current->thread.vm86_info) {
printk("no vm86_info: this is BAD\n");
do_exit(SIGSEGV);
}
set_flags(regs->eflags, VEFLAGS, VIF_MASK | current->thread.v86mask);
tmp = copy_to_user(¤t->thread.vm86_info->regs,regs, VM86_REGS_SIZE1);
tmp += copy_to_user(¤t->thread.vm86_info->regs.VM86_REGS_PART2,
®s->VM86_REGS_PART2, VM86_REGS_SIZE2);
tmp += put_user(current->thread.screen_bitmap,¤t->thread.vm86_info->screen_bitmap);
if (tmp) {
printk("vm86: could not access userspace vm86_info\n");
do_exit(SIGSEGV);
}
tss = init_tss + smp_processor_id();
#ifdef CONFIG_MOSIX
lock_mosix(); /* ptrace checks saved_esp0 under the mosix-lock */
#endif /* CONFIG_MOSIX */
tss->esp0 = current->thread.esp0 = current->thread.saved_esp0;
current->thread.saved_esp0 = 0;
ret = KVM86->regs32;
#ifdef CONFIG_MOSIX
unlock_mosix();
task_lock(current);
current->mosix.stay &= ~DSTAY_FOR_86; /* se marca la opcion de bloqueo del proceso */
task_unlock(current);
#endif /* CONFIG_MOSIX */
return ret;
}
asmlinkage int sys_vm86old()
En caso de tratarse de un proceso en emulación y de haberse iniciado la
migración antes de percatarse de tal condición, se manda el señal para
volver el proceso al UHN indicando la razón DSTAY_FOR_86.
asmlinkage int sys_vm86old(struct vm86_struct * v86)
{
struct kernel_vm86_struct info;
struct task_struct *tsk;
int tmp, ret = -EPERM;
#ifdef CONFIG_MOSIX
if(!mosix_go_home_for_reason(1, DSTAY_FOR_86))
{
ret = -ENOMEM;
goto out;
}
#endif /* CONFIG_MOSIX */
tsk = current;
if (tsk->thread.saved_esp0)
goto out;
tmp = copy_from_user(&info, v86, VM86_REGS_SIZE1);
tmp += copy_from_user(&info.regs.VM86_REGS_PART2, &v86->regs.VM86_REGS_PART2,
(long)&info.vm86plus - (long)&info.regs.VM86_REGS_PART2);
ret = -EFAULT;
if (tmp)
goto out;
memset(&info.vm86plus, 0, (int)&info.regs32 - (int)&info.vm86plus);
info.regs32 = (struct pt_regs *) &v86;
tsk->thread.vm86_info = v86;
do_sys_vm86(&info, tsk);
ret = 0; /* we never return here */
out:
return ret;
}
asmlinkage int sys_ioperm()