void proc_start_user(void) { unsigned int cur_pid = get_curid(); static int first = TRUE; kstack_switch(cur_pid); set_pdir_base(cur_pid); trap_return((void *) &uctx_pool[cur_pid]); }
static void do_cputs(trapframe *tf, uint32_t cmd) { // Print the string supplied by the user: pointer in EBX char buf[CPUTS_MAX+1]; usercopy(tf,0,buf,tf->regs.ebx,CPUTS_MAX); buf[CPUTS_MAX] = 0; cprintf("%s",buf); cprintf("%s", (char*)tf->regs.ebx); trap_return(tf); // syscall completed }
// Switch to and run a specified process, which must already be locked. void gcc_noreturn proc_run(proc *p) { // cprintf("proc_run %p\n", p); if(!spinlock_holding(&(p->lock))) panic("should have p->lock.\n"); p->runcpu = cpu_cur(); p->state = PROC_RUN; cpu_cur()->proc = p; spinlock_release(&(p->lock)); trap_return(&(p->sv.tf)); }
static void do_cputs(trapframe *tf, uint32_t cmd) { // Print the string supplied by the user: pointer in EBX // Add one for null termination char tmp[CPUTS_MAX]; usercopy(tf, 0, tmp, tf->regs.ebx, CPUTS_MAX); // Make sure it's null terminated (though it may be less than CPUTS_MAX long) //tmp[CPUTS_MAX] = 0; cprintf("%s", tmp); trap_return(tf); // syscall completed }
// 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 }
void trap (tf_t *tf) { unsigned int cur_pid; unsigned int in_kernel; cur_pid = get_curid (); set_pdir_base (0); //switch to the kernel's page table. trap_cb_t f; f = TRAP_HANDLER[get_pcpu_idx()][tf->trapno]; if (f){ f(tf); } else { KERN_WARN("No handler for user trap 0x%x, process %d, eip 0x%08x. \n", tf->trapno, cur_pid, tf->eip); } kstack_switch(cur_pid); set_pdir_base(cur_pid); trap_return((void *) tf); }
// Switch to and run a specified process, which must already be locked. void gcc_noreturn proc_run(proc *p) { if (!spinlock_holding(&p->lock)) panic("proc_run without lock"); //if (p->parent) cprintf("running child\n"); // else cprintf("running root\n"); p->state = PROC_RUN; p->runcpu = cpu_cur(); cpu_cur()->proc = p; // Enable interrupts (for preemption) p->sv.tf.eflags |= (1 << 9); p->sv.tf.ds = CPU_GDT_UDATA | 3; p->sv.tf.es = CPU_GDT_UDATA | 3; p->sv.tf.cs = CPU_GDT_UCODE | 3; p->sv.tf.ss = CPU_GDT_UDATA | 3; lcr3 (mem_phys(p->pdir)); spinlock_release(&p->lock); trap_return(&p->sv.tf); }
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 }