NetBSD-current /sbin/initが起動されるまで(3)

pack.ep_esch->es_emulはstruct emulのポインタになっており、NetBSDアプリケーションを実行する時はcompat/netbsd32/netbsd32_netbsd.cに定義されているemul_netbsd32が代入されている。

const struct emul emul_netbsd32 = {
        "netbsd32",
        "/emul/netbsd32",
#ifndef __HAVE_MINIMAL_EMUL
        0,
        NULL,
        NETBSD32_SYS_syscall,
        NETBSD32_SYS_NSYSENT,
#endif
        netbsd32_sysent,
#ifdef SYSCALL_DEBUG
        netbsd32_syscallnames,
#else
        NULL,
#endif
        netbsd32_sendsig,
        trapsignal,
        NULL,
#ifdef COMPAT_16
        netbsd32_sigcode,
        netbsd32_esigcode,
        &emul_netbsd32_object,
#else
        NULL,
        NULL,
        NULL,
#endif
        netbsd32_setregs,
        NULL,
        NULL,
        NULL,
        NULL,
        NULL,
#ifdef __HAVE_SYSCALL_INTERN
        netbsd32_syscall_intern,
#else
        syscall,
#endif
        &netbsd32_sysctl_root,
        NULL,

        netbsd32_vm_default_addr,
        NULL,
        sizeof(ucontext32_t),
        startlwp32,
};

netbsd32_setregsでgrepしてみると、以下の結果が得られた:

arch/sparc64/sparc64/netbsd32_machdep.c:netbsd32_setregs(struct lwp *l, struct exec_package *pack, u_long stack)
arch/sparc64/sparc64/svr4_32_machdep.c: netbsd32_setregs(l, epp, stack);
arch/amd64/amd64/netbsd32_machdep.c:netbsd32_setregs(struct lwp *l, struct exec_package *pack, u_long stack)
arch/powerpc/include/netbsd32_machdep.h:void netbsd32_setregs (struct lwp *, struct exec_package *, u_long);

mipsには同じ関数が見当たらないのだが、arch/mips/mips/mips_machdep.cの
void setregs(l, pack, stack)
がそれに当たる関数だと思う。

/*
 * Set registers on exec.
 * Clear all registers except sp, pc, and t9.
 * $sp is set to the stack pointer passed in.  $pc is set to the entry
 * point given by the exec_package passed in, as is $t9 (used for PIC
 * code by the MIPS elf abi).
 */
void
setregs(l, pack, stack)
        struct lwp *l;
        struct exec_package *pack;
        u_long stack;
{
        struct frame *f = (struct frame *)l->l_md.md_regs;

        memset(f, 0, sizeof(struct frame));
        f->f_regs[_R_SP] = (int)stack;
        f->f_regs[_R_PC] = (int)pack->ep_entry & ~3;
        f->f_regs[_R_T9] = (int)pack->ep_entry & ~3; /* abicall requirement */
        f->f_regs[_R_SR] = PSL_USERSET;

        /*
         * Set up arguments for _start():
         *      _start(stack, obj, cleanup, ps_strings);
         *
         * Notes:
         *      - obj and cleanup are the auxiliary and termination
         *        vectors.  They are fixed up by ld.elf_so.
         *      - ps_strings is a NetBSD extension.
         */
        f->f_regs[_R_A0] = (uintptr_t)stack;
        f->f_regs[_R_A1] = 0;
        f->f_regs[_R_A2] = 0;
        f->f_regs[_R_A3] = (intptr_t)l->l_proc->p_psstr;

        if ((l->l_md.md_flags & MDP_FPUSED) && l == fpcurlwp)
                fpcurlwp = NULL;
        memset(&l->l_addr->u_pcb.pcb_fpregs, 0, sizeof(struct fpreg));
        l->l_md.md_flags &= ~MDP_FPUSED;
        l->l_md.md_ss_addr = 0;
}

struct emulでは、e_setregsの次にe_proc_execが定義されている:

struct emul {
        const char      *e_name;        /* Symbolic name */
        const char      *e_path;        /* Extra emulation path (NULL if none)*/
#ifndef __HAVE_MINIMAL_EMUL
        int             e_flags;        /* Miscellaneous flags, see above */
                                        /* Syscall handling function */
        const int       *e_errno;       /* Errno array */
        int             e_nosys;        /* Offset of the nosys() syscall */
        int             e_nsysent;      /* Number of system call entries */
#endif
        const struct sysent *e_sysent;  /* System call array */
        const char * const *e_syscallnames; /* System call name array */
                                        /* Signal sending function */
        void            (*e_sendsig)(const struct ksiginfo *,
                                          const sigset_t *);
        void            (*e_trapsignal)(struct lwp *, struct ksiginfo *);
        int             (*e_tracesig)(struct proc *, int);
        char            *e_sigcode;     /* Start of sigcode */
        char            *e_esigcode;    /* End of sigcode */
                                        /* Set registers before execution */
        struct uvm_object **e_sigobject;/* shared sigcode object */
        void            (*e_setregs)(struct lwp *, struct exec_package *,
                                          u_long);

                                        /* Per-process hooks */
        void            (*e_proc_exec)(struct proc *, struct exec_package *);

emul_netbsd32ではnetbsd32_setregsの次はNULLとされているので、proc_exec hookは実行されない。

 if (pack.ep_esch->es_emul->e_proc_exec)
                (*pack.ep_esch->es_emul->e_proc_exec)(p, &pack);

さて、プログラムをメモリにロードして、メモリ空間を用意し、レジスタをフレームに設定する所までは出来ました。
このプロセスのロードは、通常のスケジューリングによるコンテキスト切り替えから、という事でよいのかな?