Subject: Re: cpu_fork(), it bends my brain
To: None <thorpej@zembu.com>
From: Anders Magnusson <ragge@ludd.luth.se>
List: port-vax
Date: 05/25/2000 13:18:19
> Hi folks...
> 
> I'm hoping that someone here (HI RAGGE! :-) can explain to me how
> the VAX port's cpu_fork() works.  I've figured out cpu_fork() on
> every other patform, but the VAX has me stumped.
> 
This only shows that you don't have enough knowledge about real computers. :-)
You should get a VAX, Jason :-)

> However, on the VAX, it sems to be "Go directly to userspace, do
> not pass GO, do not collect $200."  Now, cpu_set_kpc() does reference
> `sret' (eek, some historical name?) ... however, all users of
> cpu_set_kpc() never return to userspace ... aaaaaah, except for
> start_init()!
> 
Ok, simple principle:
cpu_fork() is called to duplicate another process. Switching between
processes is done with two instructions; svpctx and ldpctx (compare with
the Alpha PAL call swpctx). The PCB is stored/loaded at the bottom of
the u. area. A fork is a result of a system call. With all this knowledge
a new PCB (for the new process) is created based on the information in
the trap frame from the parent's system call, so when swtch() is called
the next time the new process PCB is loaded that has the state the parent
process will have after the system call returns. Simple, eh? Was it 
understandable? More code description: (nyproc is the new process' PCB).

        /* Set up internal defs in PCB. */
        nyproc->iftrap = NULL;			  <- Not doing copyin/out
        nyproc->KSP = (u_int)p2->p_addr + USPACE; <- kernel stack pointer 

        /* General registers as taken from userspace */
        /* trapframe should be synced with pcb */
        bcopy(&tf->r2,&nyproc->R[2],10*sizeof(int)); <- copy regs from trap
							frame to PCB

        /*
         * If specified, give the child a different stack.
         */
        if (stack != NULL)
                tf->sp = (u_long)stack + stacksize;

        nyproc->AP = tf->ap;	<- copy other registers also
        nyproc->FP = tf->fp;
        nyproc->USP = tf->sp;
        nyproc->PC = tf->pc;	<- user space program counter after trap
        nyproc->PSL = tf->psl & ~PSL_C; <- PSL have privileges of process
					   (kernel/user privileges)
        nyproc->R[0] = p1->p_pid; /* parent pid. (shouldn't be needed) */
        nyproc->R[1] = 1;	<- R0/R1 have return values

        return; /* Child is ready. Parent, return! */

Hope this is more clear...

> Ok, so is it the case that init's PCB is used to seed all of the
> others in cpu_fork()?
> 
No, the parent's trap frame contains everything needed.

> Basically, I'm needing to eliminate cpu_set_kpc() (sort of) -- cpu_fork()
> needs to take the function and argument to eliminate a race in a
> multiprocessor environment.
> 
That would be simple. If it is based on the same premises (a process is
forked) then PC must be set (if provided) and an argument list must be
created on the kernel stack (same as cpu_set_kpc() does today). 
I assume that you don't provide a PC if it's a normal fork :-)

If you want to, then I can fix it on VAX if you do it on the other arch's.

-- Ragge