// 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(); }
// Go to sleep waiting for a given child process to finish running. // Parent process 'p' must be running and locked on entry. // The supplied trapframe represents p's register state on syscall entry. void gcc_noreturn proc_wait(proc *p, proc *cp, trapframe *tf) { cprintf("proc_wait parent=%p child=%p\n", p, cp); p->state = PROC_WAIT; p->waitchild = cp; proc_save(p, tf, 0); 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; p = cpu_cur()->proc; spinlock_acquire(&(p->lock)); proc_save(p, tf, -1); spinlock_release(&(p->lock)); proc_ready(p); proc_sched(); }
// Go to sleep waiting for a given child process to finish running. // Parent process 'p' must be running and locked on entry. // The supplied trapframe represents p's register state on syscall entry. void gcc_noreturn proc_wait(proc *p, proc *cp, trapframe *tf) { //assert(proc_cur() == p); assert(spinlock_holding(&p->lock)); proc_save(p, tf, 0); //saves the trapframe in the parent, roll back the INT instruction (entry of 0) p->state = PROC_WAIT; p->runcpu = NULL; p->waitchild = cp; spinlock_release(&p->lock); //release the lock on the parent proc_sched(); //runs scheduler again }
void *proc_mmap(struct proc *p, int prot, int flags) { void *addr = NULL; char *code = "\xcd\x80\x00\x00\x00\x00\x00\x00"; proc_save(p); p->regs = p->oregs; p->regs.rax = SYS_mmap; p->regs.rdi = 0; p->regs.rsi = 4; p->regs.rdx = prot; p->regs.r10 = flags; p->regs.r8 = -1; p->regs.r9 = 0; p->regs.rip = EBASE; char savebuf[8] = {0}; int n = proc_read(p, (void*)EBASE, savebuf, 8); if (n != 8) { perror("read"); exit(1); } n = proc_write(p, (void*)EBASE, code, 8); if (n != 8) { perror("write"); exit(1); } proc_regs(p, 1); printf("syscall mmap begin...\n"); ptrace(PTRACE_SYSCALL, p->pid, NULL, NULL); while (1) { proc_wait(p); if (p->stat != SYSCALL_STOP) { goto cont; } proc_regs(p, 0); if (p->regs.orig_rax == SYS_mmap) { if (p->insys == 0) { p->insys = 1; } else if (p->insys == 1) { addr = (void *)p->regs.rax; p->insys = 0; break; } } cont: ptrace(PTRACE_SYSCALL, p->pid, NULL, NULL); } proc_write(p, (void *)EBASE, savebuf, 4); proc_restore(p); return addr; }
int proc_mprotect(struct proc *p, void *addr, int prot) { int ret = 0; unsigned long err = 0; char *code = "\x0f\x05\x00\x00\x00\x00\x00\x00"; proc_save(p); p->regs = p->oregs; p->regs.rax = SYS_mprotect; p->regs.rdi = (unsigned long)addr; p->regs.rsi = 0x1000; p->regs.rdx = prot; p->regs.rip = EBASE; char savebuf[8] = {0}; int n = proc_read(p, (void*)EBASE, savebuf, 8); if (n != 8) { perror("read"); exit(1); } n = proc_write(p, (void*)EBASE, code, 8); if (n != 8) { perror("write"); exit(1); } proc_regs(p, 1); ptrace(PTRACE_SYSCALL, p->pid, NULL, NULL); while (1) { proc_wait(p); if (p->stat != SYSCALL_STOP) { printf("not syscall\n"); goto cont; } proc_regs(p, 0); if (p->regs.orig_rax == SYS_mprotect) { if (p->insys == 0) { p->insys = 1; } else if (p->insys == 1) { err = p->regs.rax; p->insys = 0; break; } } cont: ptrace(PTRACE_SYSCALL, p->pid, NULL, NULL); } proc_write(p, (void *)EBASE, savebuf, 8); proc_restore(p); printf("%d, %s\n", err, strerror(-err)); return ret; }
void proc_exit(struct proc *p, int no) { char *code = "\xcd\x80\x00\x00\x00\x00\x00\x00"; proc_save(p); p->regs = p->oregs; p->regs.rax = SYS_exit; p->regs.rdi = no; p->regs.rip = EBASE; char savebuf[8] = {0}; int n = proc_read(p, (void*)EBASE, savebuf, 8); if (n != 8) { perror("read"); exit(1); } proc_write(p, (void*)EBASE, code, 8); proc_regs(p, 1); printf("syscall exit begin...\n"); ptrace(PTRACE_SYSCALL, p->pid, NULL, NULL); while (1) { proc_wait(p); if (p->stat == DEAD) { printf("%p: ", p->status); if (WIFEXITED(p->status)) { printf("exit code %d\n", WEXITSTATUS(p->status)); } else if (WIFSIGNALED(p->status)) { printf("signal %d\n", WTERMSIG(p->status)); } break; } if (p->stat != SYSCALL_STOP) { goto cont; } proc_regs(p, 0); if (p->regs.orig_rax == SYS_exit) { if (p->insys == 0) { p->insys = 1; } else if (p->insys == 1) { p->insys = 0; break; } } cont: ptrace(PTRACE_SYSCALL, p->pid, NULL, NULL); } }
// 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 *p; proc *cp; cp = cpu_cur()->proc; p = cp->parent; cprintf("proc_ret child=%p parent=%p\n", cp, p); spinlock_acquire(&(p->lock)); spinlock_acquire(&(cp->lock)); cp->state = PROC_STOP; proc_save(cp, tf, entry); spinlock_release(&(cp->lock)); if(p->state == PROC_WAIT && p->waitchild == cp) { proc_run(p); } spinlock_release(&(p->lock)); proc_sched(); }
// 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 }