\newpage
%===========================================================================
%       x.12 > ARCH
%===========================================================================
\pagestyle{empty}
\begin{latexonly}
\ifpdf
 \begin{figure}[htbp]
%      \includegraphics[bb = -250 220 0 0, scale=1]{./TuXes/tux-.jpg}
 \end{figure}
 \vspace{5in}
\else
 \begin{figure}
%      \includegraphics[-275,650][0,0]{./TuXes/tux-}
 \end{figure}
\fi
\hfill\line(1,0){400}
\end{latexonly}
\topmargin 1in
\section{{\tt ./arch/*}}
\begin{latexonly}
\line(1,0){400}
\begin{verbatim}
The arch subdirectory contains all of the architecture specific kernel
code. It has further subdirectories, one per supported architecture.

patching file arch/i386/config.in
patching file arch/i386/defconfig
patching file arch/i386/kernel/entry.S
patching file arch/i386/kernel/i387.c
patching file arch/i386/kernel/ioport.c
patching file arch/i386/kernel/Makefile
patching file arch/i386/kernel/offset.c
patching file arch/i386/kernel/process.c
patching file arch/i386/kernel/ptrace.c
patching file arch/i386/kernel/signal.c
patching file arch/i386/kernel/sys_i386.c
patching file arch/i386/kernel/traps.c
patching file arch/i386/kernel/vm86.c
patching file arch/i386/lib/usercopy.c
patching file arch/i386/mm/fault.c
patching file arch/ia64/kernel/entry.S
\end{verbatim}
\newpage
\end{latexonly}
\topmargin 0in
\pagestyle{fancy}
%===========================================================================
\subsection{{\em config.in}}
Se configura el men\'u de openMosix que se mostrar\'an en el {\em front-end} de
configuraci\'on, invocado por ejemplo por el comando {\tt make
  menuconfig}. V\'ease el c\'odigo:

\begin{verbatim}
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
\end{verbatim}
%---------------------------------------------------------------------------
\subsection{{\em defconfig}}
Se guardar\'an todas las opciones del kernel seleccionadas por el usuario.
%---------------------------------------------------------------------------
\subsection{{\em entry.S}}
Este fichero contiene todas las rutinas que manejan las llamadas a
sistema. Tambi\'en implementa el gestor de interrupciones para los cambios de
contexto en un {\em switch} de procesos.

\begin{verbatim}
#ifdef CONFIG_MOSIX
#include "mosasm.H"                   /*  libreria de codigo ensamblador de openMosix */  
#endif /* CONFIG_MOSIX */

\end{verbatim}
Para pasar de modo sistema a modo usuario:
\begin{verbatim}
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
\end{verbatim}
%---------------------------------------------------------------------------
\subsection{{\em i387.c}}
Guarda el contexto de los registros eprtenecientes al coprocesador i387.
%---------------------------------------------------------------------------
\subsection{{\em ioport.c}}
Este fichero gestiona un mapa de bits que corresponden a los permisos que
posee un proceso sobre los dispositivos de E/S.

\vspace{.2in}
\psshadowbox{{\tt static void set\_bitmap()}}

\vspace{.1in}
Configura la m\'ascara de permisos, esto no difiere del codigo del kernel {\em
  vanilla} de Linux.
Al mapa {\em bitmap} se guarda el valor {\em turn\_on}.
\begin{verbatim}
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;
        }
}\end{verbatim}

\vspace{.2in}
\psshadowbox{{\tt asmlinkage int sys\_ioperm()}}

\vspace{.1in}
Esta funci\'on modifica los permisos de E/S para el proceso en curso.
Se invocar\'a 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.
\begin{verbatim}
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;
}
\end{verbatim}
%---------------------------------------------------------------------------
\subsection{{\em offset.c}}
Este fichero proporciona rutinas a las librerr\'\i as utilizadas en {\tt
  entry.S} para las operaciones espec\'\i ficas de openMosix. Como:
\begin{itemize}
  \item Desplazamientos -{\em offsets}- constantes para los registros
  contenidos en la estructura {\em task\_struct}.
  \item Bits para tests de {\tt current-$>$dflags}
  \item Una copia de la tabla de llamadas a sistema -{\tt
  remote\_sys\_call\_table}- con todas las llamadas a sistema precedidas por
  el prefijo {\em remote\_}.
\end{itemize}
%---------------------------------------------------------------------------
\subsection{{\em ptrace.c}}
Configura y gestiona los registros SSE i FXSR de las arquitecturas Intel x86, a partir
del P III-. SSE es el acr\'onimo de {\em Streaming SIMD Extensions} y mejora
el rendimiento de la arquitectura Intel en 4 vesantes:
\begin{itemize}
  \item 8 nuevos registros de punto flotante de tama\~{n}o 128bit con
  direccionamiento directo
  \item 50 nuevas instrucciones para trabajar con paquetes de datos de punto
  flotante
  \item 8 nuevas instrucciones para el control de la cache para los datos MMX
  \item 12 nuevas instrucciones de extensi\'on de MMX.
\end{itemize}
%---------------------------------------------------------------------------
\subsection{{\em signal.c}}
En este fichero se maneja todo lo referente a las se\~{n}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 {\em remote} y {\em deputy}- la
comunicaci\'on tambi\'en debe ser posible, adem\'as de
transparente. Igualmente tiene que ser posible hacer llegar a {\em remote} el
se\~{n}al para informarle de su vuelta, {\em etc.}

\vspace{.2in}
\psshadowbox{{\tt int copy\_siginfo\_to\_user()}}

\vspace{.1in}
Para que el \'area de usuario est\'e informado del estado de los se\~{n}ales,
controlado por el \'area de kernel, se le debe pasar la informaci\'on sobre el
mapa de interrupciones.

En procesos migrados esto es importante, puesto que supone una comunicaci\'on
entre {\em remote} y {\em deputy}.
\begin{verbatim}
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 */
        }
}
\end{verbatim}

\vspace{.2in}
\psshadowbox{{\tt asmlinkage int sys\_sigreturn()}}

\vspace{.1in}
Env\'\i a el se\~{n}al para mandar de regreso el {\em remote}.
\begin{verbatim}
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 */
\end{verbatim}
La estructura {\tt sigframe} contiene:

        char *pretcode;\\
        int sig;\\
        struct sigcontext sc;\\
        struct \_fpstate fpstate;\\
        unsigned long extramask[\_NSIG\_WORDS-1];\\
        char retcode[8];\\

\begin{verbatim}
        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;
}       
\end{verbatim}

\vspace{.2in}
\psshadowbox{{\tt asmlinkage int handle\_signal()}}

\vspace{.1in}
Esta rutina atiende a las se\~{n}ales que recibe un proceso.
\begin{verbatim}
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 */ 
        }
}
\end{verbatim}
%---------------------------------------------------------------------------
\subsection{{\em vm86.c}}
Se gestiona la ejecuci\'on de los procesos en emulaci\'on vm86.
La mayor aportaci\'on de c\'odigo openMosix en esta secci\'on se debe a que
a\'un no se permite la ejecuci\'on de tales procesos estando migrados, es un
aspecto que debe controlarse.

\vspace{.2in}
\psshadowbox{{\tt asmlinkage int save\_v86\_state()}}

\vspace{.1in}
Guarda el estado del proceso en emulaci\'on. Se le indica la opci\'on de
bloqueo para que PPM no intente migrarlo.

\begin{verbatim}
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;
}
\end{verbatim}

\vspace{.2in}
\psshadowbox{{\tt asmlinkage int sys\_vm86old()}}

\vspace{.1in}
En caso de tratarse de un proceso en emulaci\'on y de haberse iniciado la
migraci\'on antes de percatarse de tal condici\'on, se manda el se\~{n}al para
volver el proceso al UHN indicando la raz\'on DSTAY\_FOR\_86.
\begin{verbatim}
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;
}
\end{verbatim}
%---------------------------------------------------------------------------

\vspace{.2in}
\psshadowbox{{\tt asmlinkage int sys\_ioperm()}}

\vspace{.1in}

