As the title says, I am having trouble debugging my implementation of sys_fork into OS161. I should preface this with the fact that I am engineer by degree and so my C is a bit rusty. If I understand how this is all working, a user level program calls fork which traps to the kernel (this is luckily handled for us). From tehre we enter sys_fork. The idea is that sys_fork will make a copy of the calling process's address space via as_copy. I then save the existing trapframe to the heap so it's accessible to the child. Finally, I call thread_fork with the entry point being md_forkentry. My implemenation of md_forketnry is quit simple. I simply set the current thread's address space to the one created in the parent's acll to as_copy. I copy the trapframe off the heap and edit the values so that the return fucntion sees the correct values. Finally I call mips_usermode(&tf) to send the child back to user mode. This is where I have problems. I get the print out that says "About to enter user mode" but then the system hangs and eventually shuts down. It does NOT do a panic, it simply chuts down after about a minute of sitting there idle. If anybody sees anything that I'm doing blatently incorrect I'd appreciate the help.

void
md_forkentry(struct trapframe *temptf, unsigned long vmspace)
{
/*
* This is the entry point for the child process
*/

kprintf("Hello! I'm the child!\n");

// Store the heap trapframe
struct trapframe tf = *temptf;

// Set the trapframe values so that the user sees the correct
// return values. Also increment the program counter so we don't
// continue to call the trap code.
tf.tf_v0 = 0;
tf.tf_a3 = 0;
tf.tf_epc += 4;

// Set the child's address space to the one set up by fork
curthread->t_vmspace = (struct addrspace *)vmspace;

// Esure that the structure copied into the heap is freed
kfree(temptf);

// Pass control back to user mode
kprintf("About to enter user mode\n");
mips_usermode(&tf);

// Panic if user mode returns
panic("User mode returned!");
}

/*
* This is the implementation of fork. It is placed here because it goes along with
* thread_fork and other kernel level thread functions
*/
int
sys_fork(struct trapframe *tf, int32_t *retval)
{
// This function is responsible for copying the address space
// of the calling process and changing the PID for the child.
// It needs to be aware that the calling process may reside in
// userspace and therefore must use the protected memory copy
// methods to ensure kernel stability. This is acomplished by
// calling copyin to make a copy of the calling address space.
// We can then use as_copy to copy the memory of the parent
// process into the child's address. Finally, we call
// thread_fork with the arguments for md_forkentry which is
// the user level process entry point.

kprintf("Entering sys_fork\n");
// Create a new thread
struct thread *newguy;
int result;

// Create a new thread
newguy = thread_create("Child");

// Copy the address space of the parent using as_copy
result = as_copy(curthread->t_vmspace,&newguy->t_vmspace);

// Copy the trapframe to the heap so it's available to the child
struct trapframe *temptf;
temptf = kmalloc(sizeof(tf));
memcpy(tf,temptf,sizeof(tf));

// Call thread_fork
result = thread_fork("Child Process", /* Function Description */
temptf, /* Trapframe */
(unsigned long)&newguy->t_vmspace, /* Child Thread address */
md_forkentry, /* Child entry point */
NULL); /* Return thread */

// Return the pid of the child to the parent process
*retval = newguy->pid;
return 0;
}