// Put the current process to sleep by "returning" to its parent process. // Used both when a process calls the SYS_RET system call explicitly, // and when a process causes an unhandled trap in user mode. // The 'entry' parameter is as in proc_save(). void gcc_noreturn proc_ret(trapframe *tf, int entry) { proc *cp = proc_cur(); proc *p = cp->parent; if (p == NULL){ if (tf->trapno != T_SYSCALL){ trap_print(tf); panic("no parent to reflect trap"); } file_io(tf); cprintf("fileio done\n"); } spinlock_acquire(&cp->lock); cp->state = PROC_STOP; cp->runcpu = NULL; proc_save(cp, tf, entry); spinlock_release(&cp->lock); spinlock_acquire(&p->lock); if (p->state == PROC_WAIT && p->waitchild == cp) { p->waitchild = NULL; proc_run(p); } spinlock_release(&p->lock); proc_sched(); }
// Yield the current CPU to another ready process. // Called while handling a timer interrupt. void gcc_noreturn proc_yield(trapframe *tf) { //proc * p = cpu_cur()->proc; proc *p = proc_cur(); proc_save(p, tf, -1); // -1 because timer interrupt proc_ready(p); proc_sched(); }
static void do_ret(trapframe *tf, uint32_t cmd) { proc *curr = proc_cur(); // cprintf("node %d return: home: %d\n", net_node, RRNODE(curr->home)); // This is not this node's home if(RRNODE(curr->home) != net_node) { // cprintf("sys_ret: %p returning home to %d\n", curr, RRNODE(curr->home)); // spinlock_release(&curr->lock); net_migrate(tf, RRNODE(curr->home), 0); } proc_ret(tf, 1); }
// Called from proc_ret() when the root process "returns" - // this function performs any new output the root process requested, // or if it didn't request output, puts the root process to sleep // waiting for input to arrive from some I/O device. void file_io(trapframe *tf) { proc *cp = proc_cur(); assert(cp == proc_root); // only root process should do this! // Note that we don't need to bother protecting ourselves // against memory access traps while accessing user memory here, // because we consider the root process a special, "trusted" process: // the whole system goes down anyway if the root process goes haywire. // This is very different from handling system calls // on behalf of arbitrary processes that might be buggy or evil. // Perform I/O with whatever devices we have access to. bool iodone = 0; iodone |= cons_io(); // Has the root process exited? if (files->exited) { cprintf("root process exited with status %d\n", files->status); done(); } //cprintf("iodone = %d\n", iodone); // We successfully did some I/O, let the root process run again. if (iodone) trap_return(tf); // No I/O ready - put the root process to sleep waiting for I/O. spinlock_acquire(&file_lock); cp->state = PROC_STOP; // we're becoming stopped cp->runcpu = NULL; // no longer running proc_save(cp, tf, 1); // save process's state spinlock_release(&file_lock); proc_sched(); // go do something else }
static void do_get(trapframe *tf, uint32_t cmd) { proc *curr = proc_cur(); spinlock_acquire(&curr->lock); // Find child index (includes node number and child number) int child_index = tf->regs.edx; uint8_t node_number = child_index >> 8; // First 8 bits are the node number uint8_t child_number = child_index & 0xff;// The last 8 bits for child number // cprintf("node %d get: dest node: %d, child: %d, home node: %d\n", // net_node, node_number, child_number, RRNODE(curr->home)); // When migrating, make sure to adjust eip! => entry == 0 // Trying to migrate home and this is not its home if(node_number == 0) { node_number = RRNODE(curr->home); } if (net_node != node_number) { // cprintf("sys_get: %p migrating to %d\n", curr, node_number); spinlock_release(&curr->lock); net_migrate(tf, node_number, 0); } proc *child = curr->child[child_number]; if(!child) child = &proc_null; // cprintf("No child process %d\n", child_index); if(child->state != PROC_STOP) proc_wait(curr, child, tf); spinlock_release(&curr->lock); // cprintf("do_get: current proc: %p, cpu_cur proc: %p\n", curr, cpu_cur()->proc); uint32_t dest = tf->regs.edi; //syscall.h uint32_t size = tf->regs.ecx; uint32_t src = tf->regs.esi; if(cmd & SYS_MEMOP) { int op = cmd & SYS_MEMOP; // Check if the destination range is okay if(dest < VM_USERLO || dest > VM_USERHI || dest + size > VM_USERHI) systrap(tf, T_GPFLT, 0); if(op == SYS_COPY) { // we have to check the source too if(src < VM_USERLO || src > VM_USERHI || src + size > VM_USERHI) systrap(tf, T_GPFLT, 0); pmap_copy(child->pdir, src, curr->pdir, dest, size); } else if(op == SYS_MERGE) { pmap_merge(child->rpdir, child->pdir, src, curr->pdir, dest, size); } else pmap_remove(curr->pdir, dest, size); } if(cmd & SYS_PERM) pmap_setperm(curr->pdir, dest, size, cmd & SYS_RW); if(cmd & SYS_REGS) usercopy(tf, 1, &child->sv, tf->regs.ebx, sizeof(procstate)); trap_return(tf); // syscall completed }
static void do_put(trapframe *tf, uint32_t cmd) { proc *curr = proc_cur(); spinlock_acquire(&curr->lock); uint32_t child_index = tf->regs.edx; uint8_t node_number = child_index >> 8 & 0xff; // First 8 bits are the node number uint8_t child_number = child_index & 0xff;// The last 8 bits for child number // cprintf("node %d put: dest node: %d, child: %d, home node: %d\n", // net_node, node_number, child_number, RRNODE(curr->home)); // When migrating, make sure to adjust eip! => entry == 0 // Trying to migrate home and this is not its home if(node_number == 0) { node_number = RRNODE(curr->home); } if (net_node != node_number) { // cprintf("sys_put: %p migrating to %d\n", curr, RRNODE(curr->home)); spinlock_release(&curr->lock); net_migrate(tf, node_number, 0); } proc *child = curr->child[child_number]; if(!child) child = proc_alloc(curr, child_number); if(child->state != PROC_STOP) proc_wait(curr, child, tf); spinlock_release(&curr->lock); // cprintf("do_put: current proc: %p, cpu_cur proc: %p\n", curr, cpu_cur()->proc); if(cmd & SYS_REGS) { usercopy(tf, 0, &child->sv, tf->regs.ebx, sizeof(procstate)); child->sv.tf.ds = CPU_GDT_UDATA | 3; child->sv.tf.es = CPU_GDT_UDATA | 3; child->sv.tf.cs = CPU_GDT_UCODE | 3; child->sv.tf.ss = CPU_GDT_UDATA | 3; child->sv.tf.eflags &= FL_USER; child->sv.tf.eflags |= FL_IF; } uint32_t dest = tf->regs.edi; //syscall.h uint32_t size = tf->regs.ecx; uint32_t src = tf->regs.esi; if(cmd & SYS_MEMOP) { int op = cmd & SYS_MEMOP; // Check if the destination range is okay if(dest < VM_USERLO || dest > VM_USERHI || dest + size > VM_USERHI) systrap(tf, T_GPFLT, 0); if(op == SYS_COPY) { // we have to check the source too if(src < VM_USERLO || src > VM_USERHI || src + size > VM_USERHI) systrap(tf, T_GPFLT, 0); pmap_copy(curr->pdir, src, child->pdir, dest, size); } else pmap_remove(child->pdir, dest, size); } if(cmd & SYS_PERM) pmap_setperm(child->pdir, dest, size, cmd & SYS_RW); if(cmd & SYS_SNAP) // copy pdir to rpdir pmap_copy(child->pdir, VM_USERLO, child->rpdir, VM_USERLO, VM_USERHI-VM_USERLO); if(cmd & SYS_START) proc_ready(child); trap_return(tf); // syscall completed }
static void do_get(trapframe *tf, uint32_t cmd) { proc *p = proc_cur(); assert(p->state == PROC_RUN && p->runcpu == cpu_cur()); //cprintf("GET proc %x eip %x esp %x cmd %x\n", p, tf->eip, tf->esp, cmd); spinlock_acquire(&p->lock); // Find the named child process; DON'T create if it doesn't exist uint32_t cn = tf->regs.edx & 0xff; proc *cp = p->child[cn]; if (!cp) cp = &proc_null; // Synchronize with child if necessary. if (cp->state != PROC_STOP) proc_wait(p, cp, tf); // Since the child is now stopped, it's ours to control; // we no longer need our process lock - // and we don't want to be holding it if usercopy() below aborts. spinlock_release(&p->lock); // Get child's general register state if (cmd & SYS_REGS) { int len = offsetof(procstate, fx); // just integer regs if (cmd & SYS_FPU) len = sizeof(procstate); // whole shebang usercopy(tf, 1, &cp->sv, tf->regs.ebx, len); // Copy child process's trapframe into user space procstate *cs = (procstate*) tf->regs.ebx; memcpy(cs, &cp->sv, len); } uint32_t sva = tf->regs.esi; uint32_t dva = tf->regs.edi; uint32_t size = tf->regs.ecx; switch (cmd & SYS_MEMOP) { case 0: // no memory operation break; case SYS_COPY: case SYS_MERGE: // validate source region if (PTOFF(sva) || PTOFF(size) || sva < VM_USERLO || sva > VM_USERHI || size > VM_USERHI-sva) systrap(tf, T_GPFLT, 0); // fall thru... case SYS_ZERO: // validate destination region if (PTOFF(dva) || PTOFF(size) || dva < VM_USERLO || dva > VM_USERHI || size > VM_USERHI-dva) systrap(tf, T_GPFLT, 0); switch (cmd & SYS_MEMOP) { case SYS_ZERO: // zero memory and clear permissions pmap_remove(p->pdir, dva, size); break; case SYS_COPY: // copy from local src to dest in child pmap_copy(cp->pdir, sva, p->pdir, dva, size); break; case SYS_MERGE: // merge from local src to dest in child pmap_merge(cp->rpdir, cp->pdir, sva, p->pdir, dva, size); break; } break; default: systrap(tf, T_GPFLT, 0); } if (cmd & SYS_PERM) { // validate destination region if (PGOFF(dva) || PGOFF(size) || dva < VM_USERLO || dva > VM_USERHI || size > VM_USERHI-dva) systrap(tf, T_GPFLT, 0); if (!pmap_setperm(p->pdir, dva, size, cmd & SYS_RW)) panic("pmap_get: no memory to set permissions"); } if (cmd & SYS_SNAP) systrap(tf, T_GPFLT, 0); // only valid for PUT trap_return(tf); // syscall completed }
static void do_put(trapframe *tf, uint32_t cmd) { proc *p = proc_cur(); assert(p->state == PROC_RUN && p->runcpu == cpu_cur()); cprintf("PUT proc %x eip %x esp %x cmd %x\n", p, tf->eip, tf->esp, cmd); spinlock_acquire(&p->lock); // Find the named child process; create if it doesn't exist uint32_t cn = tf->regs.edx & 0xff; proc *cp = p->child[cn]; if (!cp) { cp = proc_alloc(p, cn); if (!cp) // XX handle more gracefully panic("sys_put: no memory for child"); } // Synchronize with child if necessary. if (cp->state != PROC_STOP) proc_wait(p, cp, tf); // Since the child is now stopped, it's ours to control; // we no longer need our process lock - // and we don't want to be holding it if usercopy() below aborts. spinlock_release(&p->lock); // Put child's general register state if (cmd & SYS_REGS) { int len = offsetof(procstate, fx); // just integer regs if (cmd & SYS_FPU) len = sizeof(procstate); // whole shebang usercopy(tf,0,&cp->sv, tf->regs.ebx, len); // Copy user's trapframe into child process procstate *cs = (procstate*) tf->regs.ebx; memcpy(&cp->sv, cs, len); // Make sure process uses user-mode segments and eflag settings cp->sv.tf.ds = CPU_GDT_UDATA | 3; cp->sv.tf.es = CPU_GDT_UDATA | 3; cp->sv.tf.cs = CPU_GDT_UCODE | 3; cp->sv.tf.ss = CPU_GDT_UDATA | 3; cp->sv.tf.eflags &= FL_USER; cp->sv.tf.eflags |= FL_IF; // enable interrupts } uint32_t sva = tf->regs.esi; uint32_t dva = tf->regs.edi; uint32_t size = tf->regs.ecx; switch (cmd & SYS_MEMOP) { case 0: // no memory operation break; case SYS_COPY: // validate source region if (PTOFF(sva) || PTOFF(size) || sva < VM_USERLO || sva > VM_USERHI || size > VM_USERHI-sva) systrap(tf, T_GPFLT, 0); // fall thru... case SYS_ZERO: // validate destination region if (PTOFF(dva) || PTOFF(size) || dva < VM_USERLO || dva > VM_USERHI || size > VM_USERHI-dva) systrap(tf, T_GPFLT, 0); switch (cmd & SYS_MEMOP) { case SYS_ZERO: // zero memory and clear permissions pmap_remove(cp->pdir, dva, size); break; case SYS_COPY: // copy from local src to dest in child pmap_copy(p->pdir, sva, cp->pdir, dva, size); break; } break; default: systrap(tf, T_GPFLT, 0); } if (cmd & SYS_PERM) { // validate destination region if (PGOFF(dva) || PGOFF(size) || dva < VM_USERLO || dva > VM_USERHI || size > VM_USERHI-dva) systrap(tf, T_GPFLT, 0); if (!pmap_setperm(cp->pdir, dva, size, cmd & SYS_RW)) panic("pmap_put: no memory to set permissions"); } if (cmd & SYS_SNAP) // Snapshot child's state pmap_copy(cp->pdir, VM_USERLO, cp->rpdir, VM_USERLO, VM_USERHI-VM_USERLO); // Start the child if requested if (cmd & SYS_START) proc_ready(cp); trap_return(tf); // syscall completed }