// 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 }
// 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 }
// Called first from entry.S on the bootstrap processor, // and later from boot/bootother.S on all other processors. // As a rule, "init" functions in PIOS are called once on EACH processor. void init(void) { extern char start[], edata[], end[]; // Before anything else, complete the ELF loading process. // Clear all uninitialized global data (BSS) in our program, // ensuring that all static/global variables start out zero. if (cpu_onboot()) memset(edata, 0, end - edata); // Initialize the console. // Can't call cprintf until after we do this! cons_init(); extern uint8_t _binary_obj_boot_bootother_start[], _binary_obj_boot_bootother_size[]; uint8_t *code = (uint8_t*)lowmem_bootother_vec; memmove(code, _binary_obj_boot_bootother_start, (uint32_t) _binary_obj_boot_bootother_size); // Lab 1: test cprintf and debug_trace cprintf("1234 decimal is %o octal!\n", 1234); debug_check(); // Initialize and load the bootstrap CPU's GDT, TSS, and IDT. cpu_init(); trap_init(); // Physical memory detection/initialization. // Can't call mem_alloc until after we do this! mem_init(); // Lab 2: check spinlock implementation if (cpu_onboot()) spinlock_check(); // Initialize the paged virtual memory system. pmap_init(); // Find and start other processors in a multiprocessor system mp_init(); // Find info about processors in system pic_init(); // setup the legacy PIC (mainly to disable it) ioapic_init(); // prepare to handle external device interrupts lapic_init(); // setup this CPU's local APIC cpu_bootothers(); // Get other processors started // cprintf("CPU %d (%s) has booted\n", cpu_cur()->id, // cpu_onboot() ? "BP" : "AP"); file_init(); // Create root directory and console I/O files // Lab 4: uncomment this when you can handle IRQ_SERIAL and IRQ_KBD. //cons_intenable(); // Let the console start producing interrupts // Initialize the process management code. proc_init(); // Initialize the process management code. proc_init(); if(!cpu_onboot()) proc_sched(); proc *root = proc_root = proc_alloc(NULL,0); elfhdr *ehs = (elfhdr *)ROOTEXE_START; assert(ehs->e_magic == ELF_MAGIC); proghdr *phs = (proghdr *) ((void *) ehs + ehs->e_phoff); proghdr *ep = phs + ehs->e_phnum; for (; phs < ep; phs++) { if (phs->p_type != ELF_PROG_LOAD) continue; void *fa = (void *) ehs + ROUNDDOWN(phs->p_offset, PAGESIZE); uint32_t va = ROUNDDOWN(phs->p_va, PAGESIZE); uint32_t zva = phs->p_va + phs->p_filesz; uint32_t eva = ROUNDUP(phs->p_va + phs->p_memsz, PAGESIZE); uint32_t perm = SYS_READ | PTE_P | PTE_U; if(phs->p_flags & ELF_PROG_FLAG_WRITE) perm |= SYS_WRITE | PTE_W; for (; va < eva; va += PAGESIZE, fa += PAGESIZE) { pageinfo *pi = mem_alloc(); assert(pi != NULL); if(va < ROUNDDOWN(zva, PAGESIZE)) memmove(mem_pi2ptr(pi), fa, PAGESIZE); else if (va < zva && phs->p_filesz) { memset(mem_pi2ptr(pi),0, PAGESIZE); memmove(mem_pi2ptr(pi), fa, zva-va); } else memset(mem_pi2ptr(pi), 0, PAGESIZE); pte_t *pte = pmap_insert(root->pdir, pi, va, perm); assert(pte != NULL); } } root->sv.tf.eip = ehs->e_entry; root->sv.tf.eflags |= FL_IF; pageinfo *pi = mem_alloc(); assert(pi != NULL); pte_t *pte = pmap_insert(root->pdir, pi, VM_STACKHI-PAGESIZE, SYS_READ | SYS_WRITE | PTE_P | PTE_U | PTE_W); assert(pte != NULL); root->sv.tf.esp = VM_STACKHI; proc_ready(root); proc_sched(); // Initialize the I/O system. // Lab 1: change this so it enters user() in user mode, // running on the user_stack declared above, // instead of just calling user() directly. user(); // FIXME: Maybe get rid of this }