Subsecciones

- 6.3.1 config.in
- 6.3.2 defconfig
- 6.3.3 entry.S
- 6.3.4 i387.c
- 6.3.5 ioport.c
- 6.3.6 offset.c
- 6.3.7 ptrace.c
- 6.3.8 signal.c
- 6.3.9 vm86.c

# 6.3 `./arch/*`

## 6.3.1 config.in

Se configura el menú de openMosix que se mostrarán en el front-end de configuración, invocado por ejemplo por el comando `make menuconfig`. Véase el código:

    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

## 6.3.2 defconfig

Se guardarán todas las opciones del kernel seleccionadas por el usuario.

## 6.3.3 entry.S

Este fichero contiene todas las rutinas que manejan las llamadas a sistema. También implementa el gestor de interrupciones para los cambios de contexto en un switch de procesos.

    #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

## 6.3.4 i387.c

Guarda el contexto de los registros eprtenecientes al coprocesador i387.

## 6.3.5 ioport.c

Este fichero gestiona un mapa de bits que corresponden a los permisos que posee un proceso sobre los dispositivos de E/S.

`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 = &current->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;
    }

## 6.3.6 offset.c

Este fichero proporciona rutinas a las librerrías utilizadas en `entry.S` para las operaciones específicas de openMosix. Como:

- Desplazamientos -offsets- constantes para los registros contenidos en la estructura task_struct.
- Bits para tests de `current-dflags`
- Una copia de la tabla de llamadas a sistema -`remote_sys_call_table`- con todas las llamadas a sistema precedidas por el prefijo remote_.

## 6.3.7 ptrace.c

Configura y gestiona los registros SSE i FXSR de las arquitecturas Intel x86, a partir del P III-. SSE es el acrónimo de Streaming SIMD Extensions y mejora el rendimiento de la arquitectura Intel en 4 vesantes:

- 8 nuevos registros de punto flotante de tamaño 128bit con direccionamiento directo
- 50 nuevas instrucciones para trabajar con paquetes de datos de punto flotante
- 8 nuevas instrucciones para el control de la cache para los datos MMX
- 12 nuevas instrucciones de extensión de MMX.

## 6.3.8 signal.c

En este fichero se maneja todo lo referente a las señales qe el sistema puede enviar a los procesos. El parche openMosix debe hacer considerables modificaciones, puesto que en los procesos migrados -procesos divididos en remote y deputy- la comunicación también debe ser posible, además de transparente. Igualmente tiene que ser posible hacer llegar a remote el señal para informarle de su vuelta, etc.

`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(&current->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(&current->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(&current->sigmask_lock);   /* se bloquea la recepcion de interrupciones para el proceso */
                    sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
                    sigaddset(&current->blocked,sig);        /* se actualiza el estado de las interrupciones del proceso */
                    recalc_sigpending(current);              /* se atiende a las interrupciones pendientes */
                    spin_unlock_irq(&current->sigmask_lock); /* se desbloquea */
            }
    }

## 6.3.9 vm86.c

Se gestiona la ejecución de los procesos en emulación vm86. La mayor aportación de código openMosix en esta sección se debe a que aún no se permite la ejecución de tales procesos estando migrados, es un aspecto que debe controlarse.

`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(&current->thread.vm86_info->regs,regs, VM86_REGS_SIZE1);
            tmp += copy_to_user(&current->thread.vm86_info->regs.VM86_REGS_PART2,
                    &regs->VM86_REGS_PART2, VM86_REGS_SIZE2);
            tmp += put_user(current->thread.screen_bitmap,&current->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()`