PUBLIC void save_fpu(struct proc *pr) { #ifdef CONFIG_SMP if (cpuid == pr->p_cpu) { if (get_cpulocal_var(fpu_owner) == pr) { disable_fpu_exception(); save_local_fpu(pr); } } else { int stopped; /* remember if the process was already stopped */ stopped = RTS_ISSET(pr, RTS_PROC_STOP); /* stop the remote process and force it's context to be saved */ smp_schedule_stop_proc_save_ctx(pr); /* * If the process wasn't stopped let the process run again. The * process is kept block by the fact that the kernel cannot run * on its cpu */ if (!stopped) RTS_UNSET(pr, RTS_PROC_STOP); } #else if (get_cpulocal_var(fpu_owner) == pr) { disable_fpu_exception(); save_local_fpu(pr); } #endif }
struct proc * arch_finish_switch_to_user(void) { char * stk; struct proc * p; #ifdef CONFIG_SMP stk = (char *)tss[cpuid].sp0; #else stk = (char *)tss[0].sp0; #endif /* set pointer to the process to run on the stack */ p = get_cpulocal_var(proc_ptr); *((reg_t *)stk) = (reg_t) p; /* make sure IF is on in FLAGS so that interrupts won't be disabled * once p's context is restored. */ p->p_reg.psw |= IF_MASK; /* Set TRACEBIT state properly. */ if(p->p_misc_flags & MF_STEP) p->p_reg.psw |= TRACEBIT; else p->p_reg.psw &= ~TRACEBIT; return p; }
void nmi_sprofile_handler(struct nmi_frame * frame) { struct proc * p = get_cpulocal_var(proc_ptr); /* * test if the kernel was interrupted. If so, save first a sample fo * kernel and than for the current process, otherwise save just the * process */ if (nmi_in_kernel(frame)) { struct proc *kern; /* * if we sample kernel, check if IDLE is scheduled. If so, * account for idle time rather than taking kernel sample */ if (p->p_endpoint == IDLE) { sprof_info.idle_samples++; sprof_info.total_samples++; return; } kern = proc_addr(KERNEL); profile_sample(kern, (void *) frame->pc); } else profile_sample(p, (void *) frame->pc); }
void smp_sched_handler(void) { unsigned flgs; unsigned cpu = cpuid; flgs = sched_ipi_data[cpu].flags; if (flgs) { struct proc * p; p = (struct proc *)sched_ipi_data[cpu].data; if (flgs & SCHED_IPI_STOP_PROC) { RTS_SET(p, RTS_PROC_STOP); } if (flgs & SCHED_IPI_SAVE_CTX) { /* all context has been saved already, FPU remains */ if (proc_used_fpu(p) && get_cpulocal_var(fpu_owner) == p) { disable_fpu_exception(); save_local_fpu(p, FALSE /*retain*/); /* we're preparing to migrate somewhere else */ release_fpu(p); } } if (flgs & SCHED_IPI_VM_INHIBIT) { RTS_SET(p, RTS_VMINHIBIT); } } __insn_barrier(); sched_ipi_data[cpu].flags = 0; }
PUBLIC void arch_do_syscall(struct proc *proc) { /* do_ipc assumes that it's running because of the current process */ assert(proc == get_cpulocal_var(proc_ptr)); /* Make the system call, for real this time. */ proc->p_reg.retreg = do_ipc(proc->p_reg.cx, proc->p_reg.retreg, proc->p_reg.bx); }
void arch_post_init(void) { /* Let memory mapping code know what's going on at bootstrap time */ struct proc *vm; vm = proc_addr(VM_PROC_NR); get_cpulocal_var(ptproc) = vm; pg_info(&vm->p_seg.p_ttbr, &vm->p_seg.p_ttbr_v); }
void arch_do_syscall(struct proc *proc) { /* do_ipc assumes that it's running because of the current process */ assert(proc == get_cpulocal_var(proc_ptr)); /* Make the system call, for real this time. */ assert(proc->p_misc_flags & MF_SC_DEFER); proc->p_reg.retreg = do_ipc(proc->p_defer.r1, proc->p_defer.r2, proc->p_defer.r3); }
/* * This function gets always called only after smp_sched_handler() has been * already called. It only serves the purpose of acknowledging the IPI and * preempting the current process if the CPU was not idle. */ void smp_ipi_sched_handler(void) { struct proc * curr; ipi_ack(); curr = get_cpulocal_var(proc_ptr); if (curr->p_endpoint != IDLE) { RTS_SET(curr, RTS_PREEMPTED); } }
/*===========================================================================* * profile_clock_handler * *===========================================================================*/ static int profile_clock_handler(irq_hook_t *hook) { struct proc * p; p = get_cpulocal_var(proc_ptr); profile_sample(p, (void *) p->p_reg.pc); /* Acknowledge interrupt if necessary. */ arch_ack_profile_clock(); return(1); /* reenable interrupts */ }
void mem_clear_mapcache(void) { int i; for(i = 0; i < nfreepdes; i++) { struct proc *ptproc = get_cpulocal_var(ptproc); int pde = freepdes[i]; u32_t *ptv; assert(ptproc); ptv = ptproc->p_seg.p_cr3_v; assert(ptv); ptv[pde] = 0; } }
PUBLIC struct proc * arch_finish_switch_to_user(void) { char * stk; struct proc * p; #ifdef CONFIG_SMP stk = (char *)tss[cpuid].sp0; #else stk = (char *)tss[0].sp0; #endif /* set pointer to the process to run on the stack */ p = get_cpulocal_var(proc_ptr); *((reg_t *)stk) = (reg_t) p; return p; }
PUBLIC void fpu_init(void) { unsigned short cw, sw; fninit(); sw = fnstsw(); fnstcw(&cw); if((sw & 0xff) == 0 && (cw & 0x103f) == 0x3f) { /* We have some sort of FPU, but don't check exact model. * Set CR0_NE and CR0_MP to handle fpu exceptions * in native mode. */ write_cr0(read_cr0() | CR0_MP_NE); get_cpulocal_var(fpu_presence) = 1; if(_cpufeature(_CPUF_I386_FXSR)) { u32_t cr4 = read_cr4() | CR4_OSFXSR; /* Enable FXSR. */ /* OSXMMEXCPT if supported * FXSR feature can be available without SSE */ if(_cpufeature(_CPUF_I386_SSE)) cr4 |= CR4_OSXMMEXCPT; write_cr4(cr4); osfxsr_feature = 1; } else { osfxsr_feature = 0; } } else { /* No FPU presents. */ get_cpulocal_var(fpu_presence) = 0; osfxsr_feature = 0; return; } }
static void set_ttbr(struct proc *p, u32_t ttbr, u32_t *v) { /* Set process TTBR. */ p->p_seg.p_ttbr = ttbr; assert(p->p_seg.p_ttbr); p->p_seg.p_ttbr_v = v; if(p == get_cpulocal_var(ptproc)) { write_ttbr0(p->p_seg.p_ttbr); } if(p->p_nr == VM_PROC_NR) { if (arch_enable_paging(p) != OK) panic("arch_enable_paging failed"); } RTS_UNSET(p, RTS_VMINHIBIT); }
PUBLIC void context_stop_idle(void) { int is_idle; #ifdef CONFIG_SMP unsigned cpu = cpuid; #endif is_idle = get_cpu_var(cpu, cpu_is_idle); get_cpu_var(cpu, cpu_is_idle) = 0; context_stop(get_cpulocal_var_ptr(idle_proc)); if (is_idle) restart_local_timer(); #if SPROFILE if (sprofiling) get_cpulocal_var(idle_interrupted) = 1; #endif }
/*===========================================================================* * panic * *===========================================================================*/ PUBLIC void panic(const char *fmt, ...) { va_list arg; /* The system has run aground of a fatal kernel error. Terminate execution. */ if (minix_panicing == ARE_PANICING) { reset(); } minix_panicing = ARE_PANICING; if (fmt != NULL) { printf("kernel panic: "); va_start(arg, fmt); vprintf(fmt, arg); printf("\n"); } printf("kernel on CPU %d: ", cpuid); util_stacktrace(); printf("current process : "); proc_stacktrace(get_cpulocal_var(proc_ptr)); /* Abort MINIX. */ minix_shutdown(NULL); }
PUBLIC __dead void arch_shutdown(int how) { u16_t magic; vm_stop(); /* Mask all interrupts, including the clock. */ outb( INT_CTLMASK, ~0); if(minix_panicing) { unsigned char unused_ch; /* We're panicing? Then retrieve and decode currently * loaded segment selectors. */ printseg("cs: ", 1, get_cpulocal_var(proc_ptr), read_cs()); printseg("ds: ", 0, get_cpulocal_var(proc_ptr), read_ds()); if(read_ds() != read_ss()) { printseg("ss: ", 0, NULL, read_ss()); } /* Printing is done synchronously over serial. */ if (do_serial_debug) reset(); /* Print accumulated diagnostics buffer and reset. */ mb_cls(); mb_print("Minix panic. System diagnostics buffer:\n\n"); mb_print(kmess_buf); mb_print("\nSystem has panicked, press any key to reboot"); while (!mb_read_char(&unused_ch)) ; reset(); } #if USE_BOOTPARAM if (how == RBT_DEFAULT) { how = mon_return ? RBT_HALT : RBT_RESET; } if(how != RBT_RESET) { /* return to boot monitor */ outb( INT_CTLMASK, 0); outb( INT2_CTLMASK, 0); /* Return to the boot monitor. Set * the program if not already done. */ if (how != RBT_MONITOR) arch_set_params("", 1); if (mon_return) arch_monitor(); /* monitor command with no monitor: reset or poweroff * depending on the parameters */ if (how == RBT_MONITOR) { how = RBT_RESET; } } switch (how) { case RBT_REBOOT: case RBT_RESET: /* Reset the system by forcing a processor shutdown. * First stop the BIOS memory test by setting a soft * reset flag. */ magic = STOP_MEM_CHECK; phys_copy(vir2phys(&magic), SOFT_RESET_FLAG_ADDR, SOFT_RESET_FLAG_SIZE); reset(); NOT_REACHABLE; case RBT_HALT: /* Poweroff without boot monitor */ arch_bios_poweroff(); NOT_REACHABLE; case RBT_PANIC: /* Allow user to read panic message */ for (; ; ) halt_cpu(); NOT_REACHABLE; default: /* Not possible! trigger panic */ assert(how != RBT_MONITOR); assert(how != RBT_DEFAULT); assert(how < RBT_INVALID); panic("unexpected value for how: %d", how); NOT_REACHABLE; } #else /* !USE_BOOTPARAM */ /* Poweroff without boot monitor */ arch_bios_poweroff(); #endif NOT_REACHABLE; }
/*===========================================================================* * do_update * *===========================================================================*/ int do_update(struct proc * caller, message * m_ptr) { /* Handle sys_update(). Update a process into another by swapping their process * slots. */ endpoint_t src_e, dst_e; int src_p, dst_p; struct proc *src_rp, *dst_rp; struct priv *src_privp, *dst_privp; struct proc orig_src_proc; struct proc orig_dst_proc; struct priv orig_src_priv; struct priv orig_dst_priv; int i; /* Lookup slots for source and destination process. */ src_e = m_ptr->SYS_UPD_SRC_ENDPT; if(!isokendpt(src_e, &src_p)) { return EINVAL; } src_rp = proc_addr(src_p); src_privp = priv(src_rp); if(!(src_privp->s_flags & SYS_PROC)) { return EPERM; } dst_e = m_ptr->SYS_UPD_DST_ENDPT; if(!isokendpt(dst_e, &dst_p)) { return EINVAL; } dst_rp = proc_addr(dst_p); dst_privp = priv(dst_rp); if(!(dst_privp->s_flags & SYS_PROC)) { return EPERM; } assert(!proc_is_runnable(src_rp) && !proc_is_runnable(dst_rp)); /* Check if processes are updatable. */ if(!proc_is_updatable(src_rp) || !proc_is_updatable(dst_rp)) { return EBUSY; } #if DEBUG printf("do_update: updating %d (%s, %d, %d) into %d (%s, %d, %d)\n", src_rp->p_endpoint, src_rp->p_name, src_rp->p_nr, priv(src_rp)->s_proc_nr, dst_rp->p_endpoint, dst_rp->p_name, dst_rp->p_nr, priv(dst_rp)->s_proc_nr); proc_stacktrace(src_rp); proc_stacktrace(dst_rp); printf("do_update: curr ptproc %d\n", get_cpulocal_var(ptproc)->p_endpoint); #endif /* Let destination inherit the target mask from source. */ for (i=0; i < NR_SYS_PROCS; i++) { if (get_sys_bit(priv(src_rp)->s_ipc_to, i)) { set_sendto_bit(dst_rp, i); } } /* Save existing data. */ orig_src_proc = *src_rp; orig_src_priv = *(priv(src_rp)); orig_dst_proc = *dst_rp; orig_dst_priv = *(priv(dst_rp)); /* Swap slots. */ *src_rp = orig_dst_proc; *src_privp = orig_dst_priv; *dst_rp = orig_src_proc; *dst_privp = orig_src_priv; /* Adjust process slots. */ adjust_proc_slot(src_rp, &orig_src_proc); adjust_proc_slot(dst_rp, &orig_dst_proc); /* Adjust privilege slots. */ adjust_priv_slot(priv(src_rp), &orig_src_priv); adjust_priv_slot(priv(dst_rp), &orig_dst_priv); /* Swap global process slot addresses. */ swap_proc_slot_pointer(get_cpulocal_var_ptr(ptproc), src_rp, dst_rp); #if DEBUG printf("do_update: updated %d (%s, %d, %d) into %d (%s, %d, %d)\n", src_rp->p_endpoint, src_rp->p_name, src_rp->p_nr, priv(src_rp)->s_proc_nr, dst_rp->p_endpoint, dst_rp->p_name, dst_rp->p_nr, priv(dst_rp)->s_proc_nr); proc_stacktrace(src_rp); proc_stacktrace(dst_rp); printf("do_update: curr ptproc %d\n", get_cpulocal_var(ptproc)->p_endpoint); #endif #ifdef CONFIG_SMP bits_fill(src_rp->p_stale_tlb, CONFIG_MAX_CPUS); bits_fill(dst_rp->p_stale_tlb, CONFIG_MAX_CPUS); #endif return OK; }
__dead void arch_shutdown(int how) { vm_stop(); /* Mask all interrupts, including the clock. */ outb( INT_CTLMASK, ~0); if(minix_panicing) { unsigned char unused_ch; /* We're panicing? Then retrieve and decode currently * loaded segment selectors. */ printseg("cs: ", 1, get_cpulocal_var(proc_ptr), read_cs()); printseg("ds: ", 0, get_cpulocal_var(proc_ptr), read_ds()); if(read_ds() != read_ss()) { printseg("ss: ", 0, NULL, read_ss()); } /* Printing is done synchronously over serial. */ if (do_serial_debug) reset(); /* Print accumulated diagnostics buffer and reset. */ mb_cls(); mb_print("Minix panic. System diagnostics buffer:\n\n"); mb_print(kmess_buf); mb_print("\nSystem has panicked, press any key to reboot"); while (!mb_read_char(&unused_ch)) ; reset(); } if (how == RBT_DEFAULT) { how = RBT_RESET; } switch (how) { case RBT_HALT: /* Poweroff without boot monitor */ arch_bios_poweroff(); NOT_REACHABLE; case RBT_PANIC: /* Allow user to read panic message */ for (; ; ) halt_cpu(); NOT_REACHABLE; default: case RBT_REBOOT: case RBT_RESET: /* Reset the system by forcing a processor shutdown. * First stop the BIOS memory test by setting a soft * reset flag. */ reset(); NOT_REACHABLE; } NOT_REACHABLE; }
/* This function sets up a mapping from within the kernel's address * space to any other area of memory, either straight physical * memory (pr == NULL) or a process view of memory, in 4MB windows. * I.e., it maps in 4MB chunks of virtual (or physical) address space * to 4MB chunks of kernel virtual address space. * * It recognizes pr already being in memory as a special case (no * mapping required). * * The target (i.e. in-kernel) mapping area is one of the freepdes[] * VM has earlier already told the kernel about that is available. It is * identified as the 'pde' parameter. This value can be chosen freely * by the caller, as long as it is in range (i.e. 0 or higher and corresonds * to a known freepde slot). It is up to the caller to keep track of which * freepde's are in use, and to determine which ones are free to use. * * The logical number supplied by the caller is translated into an actual * pde number to be used, and a pointer to it (linear address) is returned * for actual use by phys_copy or phys_memset. */ static phys_bytes createpde( const struct proc *pr, /* Requested process, NULL for physical. */ const phys_bytes linaddr,/* Address after segment translation. */ phys_bytes *bytes, /* Size of chunk, function may truncate it. */ int free_pde_idx, /* index of the free slot to use */ int *changed /* If mapping is made, this is set to 1. */ ) { u32_t pdeval; phys_bytes offset; int pde; assert(free_pde_idx >= 0 && free_pde_idx < nfreepdes); pde = freepdes[free_pde_idx]; assert(pde >= 0 && pde < 1024); if(pr && ((pr == get_cpulocal_var(ptproc)) || !HASPT(pr))) { /* Process memory is requested, and * it's a process that is already in current page table, or * a process that is in every page table. * Therefore linaddr is valid directly, with the requested * size. */ return linaddr; } if(pr) { /* Requested address is in a process that is not currently * accessible directly. Grab the PDE entry of that process' * page table that corresponds to the requested address. */ assert(pr->p_seg.p_cr3_v); pdeval = pr->p_seg.p_cr3_v[I386_VM_PDE(linaddr)]; } else { /* Requested address is physical. Make up the PDE entry. */ pdeval = (linaddr & I386_VM_ADDR_MASK_4MB) | I386_VM_BIGPAGE | I386_VM_PRESENT | I386_VM_WRITE | I386_VM_USER; } /* Write the pde value that we need into a pde that the kernel * can access, into the currently loaded page table so it becomes * visible. */ assert(get_cpulocal_var(ptproc)->p_seg.p_cr3_v); if(get_cpulocal_var(ptproc)->p_seg.p_cr3_v[pde] != pdeval) { get_cpulocal_var(ptproc)->p_seg.p_cr3_v[pde] = pdeval; *changed = 1; } /* Memory is now available, but only the 4MB window of virtual * address space that we have mapped; calculate how much of * the requested range is visible and return that in *bytes, * if that is less than the requested range. */ offset = linaddr & I386_VM_OFFSET_MASK_4MB; /* Offset in 4MB window. */ *bytes = MIN(*bytes, I386_BIG_PAGE_SIZE - offset); /* Return the linear address of the start of the new mapping. */ return I386_BIG_PAGE_SIZE*pde + offset; }
/*===========================================================================* * lin_lin_copy * *===========================================================================*/ static int lin_lin_copy(struct proc *srcproc, vir_bytes srclinaddr, struct proc *dstproc, vir_bytes dstlinaddr, vir_bytes bytes) { u32_t addr; proc_nr_t procslot; assert(vm_running); assert(nfreepdes >= MAX_FREEPDES); assert(get_cpulocal_var(ptproc)); assert(get_cpulocal_var(proc_ptr)); assert(read_cr3() == get_cpulocal_var(ptproc)->p_seg.p_cr3); procslot = get_cpulocal_var(ptproc)->p_nr; assert(procslot >= 0 && procslot < I386_VM_DIR_ENTRIES); if(srcproc) assert(!RTS_ISSET(srcproc, RTS_SLOT_FREE)); if(dstproc) assert(!RTS_ISSET(dstproc, RTS_SLOT_FREE)); assert(!RTS_ISSET(get_cpulocal_var(ptproc), RTS_SLOT_FREE)); assert(get_cpulocal_var(ptproc)->p_seg.p_cr3_v); if(srcproc) assert(!RTS_ISSET(srcproc, RTS_VMINHIBIT)); if(dstproc) assert(!RTS_ISSET(dstproc, RTS_VMINHIBIT)); while(bytes > 0) { phys_bytes srcptr, dstptr; vir_bytes chunk = bytes; int changed = 0; #ifdef CONFIG_SMP unsigned cpu = cpuid; if (GET_BIT(srcproc->p_stale_tlb, cpu)) { changed = 1; UNSET_BIT(srcproc->p_stale_tlb, cpu); } if (GET_BIT(dstproc->p_stale_tlb, cpu)) { changed = 1; UNSET_BIT(dstproc->p_stale_tlb, cpu); } #endif /* Set up 4MB ranges. */ srcptr = createpde(srcproc, srclinaddr, &chunk, 0, &changed); dstptr = createpde(dstproc, dstlinaddr, &chunk, 1, &changed); if(changed) reload_cr3(); /* Copy pages. */ PHYS_COPY_CATCH(srcptr, dstptr, chunk, addr); if(addr) { /* If addr is nonzero, a page fault was caught. */ if(addr >= srcptr && addr < (srcptr + chunk)) { return EFAULT_SRC; } if(addr >= dstptr && addr < (dstptr + chunk)) { return EFAULT_DST; } panic("lin_lin_copy fault out of range"); /* Not reached. */ return EFAULT; } /* Update counter and addresses for next iteration, if any. */ bytes -= chunk; srclinaddr += chunk; dstlinaddr += chunk; } if(srcproc) assert(!RTS_ISSET(srcproc, RTS_SLOT_FREE)); if(dstproc) assert(!RTS_ISSET(dstproc, RTS_SLOT_FREE)); assert(!RTS_ISSET(get_cpulocal_var(ptproc), RTS_SLOT_FREE)); assert(get_cpulocal_var(ptproc)->p_seg.p_cr3_v); return OK; }
int is_fpu(void) { return get_cpulocal_var(fpu_presence); }
/*===========================================================================* * do_update * *===========================================================================*/ int do_update(struct proc * caller, message * m_ptr) { /* Handle sys_update(). Update a process into another by swapping their process * slots. */ endpoint_t src_e, dst_e; int src_p, dst_p, flags; struct proc *src_rp, *dst_rp; struct priv *src_privp, *dst_privp; struct proc orig_src_proc; struct proc orig_dst_proc; struct priv orig_src_priv; struct priv orig_dst_priv; int i, r; /* Lookup slots for source and destination process. */ flags = m_ptr->SYS_UPD_FLAGS; src_e = m_ptr->SYS_UPD_SRC_ENDPT; if(!isokendpt(src_e, &src_p)) { return EINVAL; } src_rp = proc_addr(src_p); src_privp = priv(src_rp); if(!(src_privp->s_flags & SYS_PROC)) { return EPERM; } dst_e = m_ptr->SYS_UPD_DST_ENDPT; if(!isokendpt(dst_e, &dst_p)) { return EINVAL; } dst_rp = proc_addr(dst_p); dst_privp = priv(dst_rp); if(!(dst_privp->s_flags & SYS_PROC)) { return EPERM; } assert(!proc_is_runnable(src_rp) && !proc_is_runnable(dst_rp)); /* Check if processes are updatable. */ if(!proc_is_updatable(src_rp) || !proc_is_updatable(dst_rp)) { return EBUSY; } #if DEBUG printf("do_update: updating %d (%s, %d, %d) into %d (%s, %d, %d)\n", src_rp->p_endpoint, src_rp->p_name, src_rp->p_nr, priv(src_rp)->s_proc_nr, dst_rp->p_endpoint, dst_rp->p_name, dst_rp->p_nr, priv(dst_rp)->s_proc_nr); proc_stacktrace(src_rp); proc_stacktrace(dst_rp); printf("do_update: curr ptproc %d\n", get_cpulocal_var(ptproc)->p_endpoint); printf("do_update: endpoint %d rts flags %x asyn tab %08x asyn endpoint %d grant tab %08x grant endpoint %d\n", src_rp->p_endpoint, src_rp->p_rts_flags, priv(src_rp)->s_asyntab, priv(src_rp)->s_asynendpoint, priv(src_rp)->s_grant_table, priv(src_rp)->s_grant_endpoint); printf("do_update: endpoint %d rts flags %x asyn tab %08x asyn endpoint %d grant tab %08x grant endpoint %d\n", dst_rp->p_endpoint, dst_rp->p_rts_flags, priv(dst_rp)->s_asyntab, priv(dst_rp)->s_asynendpoint, priv(dst_rp)->s_grant_table, priv(dst_rp)->s_grant_endpoint); #endif /* Let destination inherit allowed IRQ, I/O ranges, and memory ranges. */ r = inherit_priv_irq(src_rp, dst_rp); if(r != OK) { return r; } r = inherit_priv_io(src_rp, dst_rp); if(r != OK) { return r; } r = inherit_priv_mem(src_rp, dst_rp); if(r != OK) { return r; } /* Let destination inherit the target mask from source. */ for (i=0; i < NR_SYS_PROCS; i++) { if (get_sys_bit(priv(src_rp)->s_ipc_to, i)) { set_sendto_bit(dst_rp, i); } } /* Save existing data. */ orig_src_proc = *src_rp; orig_src_priv = *(priv(src_rp)); orig_dst_proc = *dst_rp; orig_dst_priv = *(priv(dst_rp)); /* Adjust asyn tables. */ adjust_asyn_table(priv(src_rp), priv(dst_rp)); adjust_asyn_table(priv(dst_rp), priv(src_rp)); /* Abort any pending send() on rollback. */ if(flags & SYS_UPD_ROLLBACK) { abort_proc_ipc_send(src_rp); } /* Swap slots. */ *src_rp = orig_dst_proc; *src_privp = orig_dst_priv; *dst_rp = orig_src_proc; *dst_privp = orig_src_priv; /* Adjust process slots. */ adjust_proc_slot(src_rp, &orig_src_proc); adjust_proc_slot(dst_rp, &orig_dst_proc); /* Adjust privilege slots. */ adjust_priv_slot(priv(src_rp), &orig_src_priv); adjust_priv_slot(priv(dst_rp), &orig_dst_priv); /* Swap global process slot addresses. */ swap_proc_slot_pointer(get_cpulocal_var_ptr(ptproc), src_rp, dst_rp); /* Swap VM request entries. */ swap_memreq(src_rp, dst_rp); #if DEBUG printf("do_update: updated %d (%s, %d, %d) into %d (%s, %d, %d)\n", src_rp->p_endpoint, src_rp->p_name, src_rp->p_nr, priv(src_rp)->s_proc_nr, dst_rp->p_endpoint, dst_rp->p_name, dst_rp->p_nr, priv(dst_rp)->s_proc_nr); proc_stacktrace(src_rp); proc_stacktrace(dst_rp); printf("do_update: curr ptproc %d\n", get_cpulocal_var(ptproc)->p_endpoint); printf("do_update: endpoint %d rts flags %x asyn tab %08x asyn endpoint %d grant tab %08x grant endpoint %d\n", src_rp->p_endpoint, src_rp->p_rts_flags, priv(src_rp)->s_asyntab, priv(src_rp)->s_asynendpoint, priv(src_rp)->s_grant_table, priv(src_rp)->s_grant_endpoint); printf("do_update: endpoint %d rts flags %x asyn tab %08x asyn endpoint %d grant tab %08x grant endpoint %d\n", dst_rp->p_endpoint, dst_rp->p_rts_flags, priv(dst_rp)->s_asyntab, priv(dst_rp)->s_asynendpoint, priv(dst_rp)->s_grant_table, priv(dst_rp)->s_grant_endpoint); #endif #ifdef CONFIG_SMP bits_fill(src_rp->p_stale_tlb, CONFIG_MAX_CPUS); bits_fill(dst_rp->p_stale_tlb, CONFIG_MAX_CPUS); #endif return OK; }
/*===========================================================================* * lin_lin_copy * *===========================================================================*/ static int lin_lin_copy(struct proc *srcproc, vir_bytes srclinaddr, struct proc *dstproc, vir_bytes dstlinaddr, vir_bytes bytes) { u32_t addr; proc_nr_t procslot; assert(get_cpulocal_var(ptproc)); assert(get_cpulocal_var(proc_ptr)); assert(read_ttbr0() == get_cpulocal_var(ptproc)->p_seg.p_ttbr); procslot = get_cpulocal_var(ptproc)->p_nr; assert(procslot >= 0 && procslot < ARM_VM_DIR_ENTRIES); if(srcproc) assert(!RTS_ISSET(srcproc, RTS_SLOT_FREE)); if(dstproc) assert(!RTS_ISSET(dstproc, RTS_SLOT_FREE)); assert(!RTS_ISSET(get_cpulocal_var(ptproc), RTS_SLOT_FREE)); assert(get_cpulocal_var(ptproc)->p_seg.p_ttbr_v); if(srcproc) assert(!RTS_ISSET(srcproc, RTS_VMINHIBIT)); if(dstproc) assert(!RTS_ISSET(dstproc, RTS_VMINHIBIT)); while(bytes > 0) { phys_bytes srcptr, dstptr; vir_bytes chunk = bytes; int changed = 0; #ifdef CONFIG_SMP unsigned cpu = cpuid; if (srcproc && GET_BIT(srcproc->p_stale_tlb, cpu)) { changed = 1; UNSET_BIT(srcproc->p_stale_tlb, cpu); } if (dstproc && GET_BIT(dstproc->p_stale_tlb, cpu)) { changed = 1; UNSET_BIT(dstproc->p_stale_tlb, cpu); } #endif /* Set up 1MB ranges. */ srcptr = createpde(srcproc, srclinaddr, &chunk, 0, &changed); dstptr = createpde(dstproc, dstlinaddr, &chunk, 1, &changed); if(changed) { reload_ttbr0(); } /* Copy pages. */ PHYS_COPY_CATCH(srcptr, dstptr, chunk, addr); if(addr) { /* If addr is nonzero, a page fault was caught. * * phys_copy does all memory accesses word-aligned (rounded * down), so pagefaults can occur at a lower address than * the specified offsets. compute the lower bounds for sanity * check use. */ vir_bytes src_aligned = srcptr & ~0x3, dst_aligned = dstptr & ~0x3; if(addr >= src_aligned && addr < (srcptr + chunk)) { return EFAULT_SRC; } if(addr >= dst_aligned && addr < (dstptr + chunk)) { return EFAULT_DST; } panic("lin_lin_copy fault out of range"); /* Not reached. */ return EFAULT; } /* Update counter and addresses for next iteration, if any. */ bytes -= chunk; srclinaddr += chunk; dstlinaddr += chunk; } if(srcproc) assert(!RTS_ISSET(srcproc, RTS_SLOT_FREE)); if(dstproc) assert(!RTS_ISSET(dstproc, RTS_SLOT_FREE)); assert(!RTS_ISSET(get_cpulocal_var(ptproc), RTS_SLOT_FREE)); assert(get_cpulocal_var(ptproc)->p_seg.p_ttbr_v); return OK; }
/*===========================================================================* * main * *===========================================================================*/ PUBLIC int main(void) { /* Start the ball rolling. */ struct boot_image *ip; /* boot image pointer */ register struct proc *rp; /* process pointer */ register int i, j; size_t argsz; /* size of arguments passed to crtso on stack */ BKL_LOCK(); /* Global value to test segment sanity. */ magictest = MAGICTEST; DEBUGEXTRA(("main()\n")); proc_init(); /* Set up proc table entries for processes in boot image. The stacks * of the servers have been added to the data segment by the monitor, so * the stack pointer is set to the end of the data segment. */ for (i=0; i < NR_BOOT_PROCS; ++i) { int schedulable_proc; proc_nr_t proc_nr; int ipc_to_m, kcalls; sys_map_t map; ip = &image[i]; /* process' attributes */ DEBUGEXTRA(("initializing %s... ", ip->proc_name)); rp = proc_addr(ip->proc_nr); /* get process pointer */ ip->endpoint = rp->p_endpoint; /* ipc endpoint */ make_zero64(rp->p_cpu_time_left); strncpy(rp->p_name, ip->proc_name, P_NAME_LEN); /* set process name */ reset_proc_accounting(rp); /* See if this process is immediately schedulable. * In that case, set its privileges now and allow it to run. * Only kernel tasks and the root system process get to run immediately. * All the other system processes are inhibited from running by the * RTS_NO_PRIV flag. They can only be scheduled once the root system * process has set their privileges. */ proc_nr = proc_nr(rp); schedulable_proc = (iskerneln(proc_nr) || isrootsysn(proc_nr)); if(schedulable_proc) { /* Assign privilege structure. Force a static privilege id. */ (void) get_priv(rp, static_priv_id(proc_nr)); /* Priviliges for kernel tasks. */ if(iskerneln(proc_nr)) { /* Privilege flags. */ priv(rp)->s_flags = (proc_nr == IDLE ? IDL_F : TSK_F); /* Allowed traps. */ priv(rp)->s_trap_mask = (proc_nr == CLOCK || proc_nr == SYSTEM ? CSK_T : TSK_T); ipc_to_m = TSK_M; /* allowed targets */ kcalls = TSK_KC; /* allowed kernel calls */ } /* Priviliges for the root system process. */ else if(isrootsysn(proc_nr)) { priv(rp)->s_flags= RSYS_F; /* privilege flags */ priv(rp)->s_trap_mask= SRV_T; /* allowed traps */ ipc_to_m = SRV_M; /* allowed targets */ kcalls = SRV_KC; /* allowed kernel calls */ priv(rp)->s_sig_mgr = SRV_SM; /* signal manager */ rp->p_priority = SRV_Q; /* priority queue */ rp->p_quantum_size_ms = SRV_QT; /* quantum size */ } /* Priviliges for ordinary process. */ else { NOT_REACHABLE; } /* Fill in target mask. */ memset(&map, 0, sizeof(map)); if (ipc_to_m == ALL_M) { for(j = 0; j < NR_SYS_PROCS; j++) set_sys_bit(map, j); } fill_sendto_mask(rp, &map); /* Fill in kernel call mask. */ for(j = 0; j < SYS_CALL_MASK_SIZE; j++) { priv(rp)->s_k_call_mask[j] = (kcalls == NO_C ? 0 : (~0)); } } else { /* Don't let the process run for now. */ RTS_SET(rp, RTS_NO_PRIV | RTS_NO_QUANTUM); } rp->p_memmap[T].mem_vir = ABS2CLICK(ip->memmap.text_vaddr); rp->p_memmap[T].mem_phys = ABS2CLICK(ip->memmap.text_paddr); rp->p_memmap[T].mem_len = ABS2CLICK(ip->memmap.text_bytes); rp->p_memmap[D].mem_vir = ABS2CLICK(ip->memmap.data_vaddr); rp->p_memmap[D].mem_phys = ABS2CLICK(ip->memmap.data_paddr); rp->p_memmap[D].mem_len = ABS2CLICK(ip->memmap.data_bytes); rp->p_memmap[S].mem_phys = ABS2CLICK(ip->memmap.data_paddr + ip->memmap.data_bytes + ip->memmap.stack_bytes); rp->p_memmap[S].mem_vir = ABS2CLICK(ip->memmap.data_vaddr + ip->memmap.data_bytes + ip->memmap.stack_bytes); rp->p_memmap[S].mem_len = 0; /* Set initial register values. The processor status word for tasks * is different from that of other processes because tasks can * access I/O; this is not allowed to less-privileged processes */ rp->p_reg.pc = ip->memmap.entry; rp->p_reg.psw = (iskerneln(proc_nr)) ? INIT_TASK_PSW : INIT_PSW; /* Initialize the server stack pointer. Take it down three words * to give crtso.s something to use as "argc", "argv" and "envp". */ if (isusern(proc_nr)) { /* user-space process? */ rp->p_reg.sp = (rp->p_memmap[S].mem_vir + rp->p_memmap[S].mem_len) << CLICK_SHIFT; argsz = 3 * sizeof(reg_t); rp->p_reg.sp -= argsz; phys_memset(rp->p_reg.sp - (rp->p_memmap[S].mem_vir << CLICK_SHIFT) + (rp->p_memmap[S].mem_phys << CLICK_SHIFT), 0, argsz); } /* scheduling functions depend on proc_ptr pointing somewhere. */ if(!get_cpulocal_var(proc_ptr)) get_cpulocal_var(proc_ptr) = rp; /* If this process has its own page table, VM will set the * PT up and manage it. VM will signal the kernel when it has * done this; until then, don't let it run. */ if(ip->flags & PROC_FULLVM) rp->p_rts_flags |= RTS_VMINHIBIT; rp->p_rts_flags |= RTS_PROC_STOP; rp->p_rts_flags &= ~RTS_SLOT_FREE; alloc_segments(rp); DEBUGEXTRA(("done\n")); } #define IPCNAME(n) { \ assert((n) >= 0 && (n) <= IPCNO_HIGHEST); \ assert(!ipc_call_names[n]); \ ipc_call_names[n] = #n; \ } IPCNAME(SEND); IPCNAME(RECEIVE); IPCNAME(SENDREC); IPCNAME(NOTIFY); IPCNAME(SENDNB); IPCNAME(SENDA); /* Architecture-dependent initialization. */ DEBUGEXTRA(("arch_init()... ")); arch_init(); DEBUGEXTRA(("done\n")); /* System and processes initialization */ DEBUGEXTRA(("system_init()... ")); system_init(); DEBUGEXTRA(("done\n")); #ifdef CONFIG_SMP if (config_no_apic) { BOOT_VERBOSE(printf("APIC disabled, disables SMP, using legacy PIC\n")); smp_single_cpu_fallback(); } else if (config_no_smp) { BOOT_VERBOSE(printf("SMP disabled, using legacy PIC\n")); smp_single_cpu_fallback(); } else { smp_init(); /* * if smp_init() returns it means that it failed and we try to finish * single CPU booting */ bsp_finish_booting(); } #else /* * if configured for a single CPU, we are already on the kernel stack which we * are going to use everytime we execute kernel code. We finish booting and we * never return here */ bsp_finish_booting(); #endif NOT_REACHABLE; return 1; }
/*===========================================================================* * kmain * *===========================================================================*/ void kmain(kinfo_t *local_cbi) { /* Start the ball rolling. */ struct boot_image *ip; /* boot image pointer */ register struct proc *rp; /* process pointer */ register int i, j; /* save a global copy of the boot parameters */ memcpy(&kinfo, local_cbi, sizeof(kinfo)); memcpy(&kmess, kinfo.kmess, sizeof(kmess)); #ifdef __arm__ /* We want to initialize serial before we do any output */ omap3_ser_init(); #endif /* We can talk now */ printf("MINIX booting\n"); /* Kernel may use bits of main memory before VM is started */ kernel_may_alloc = 1; assert(sizeof(kinfo.boot_procs) == sizeof(image)); memcpy(kinfo.boot_procs, image, sizeof(kinfo.boot_procs)); cstart(); BKL_LOCK(); DEBUGEXTRA(("main()\n")); proc_init(); if(NR_BOOT_MODULES != kinfo.mbi.mods_count) panic("expecting %d boot processes/modules, found %d", NR_BOOT_MODULES, kinfo.mbi.mods_count); /* Set up proc table entries for processes in boot image. */ for (i=0; i < NR_BOOT_PROCS; ++i) { int schedulable_proc; proc_nr_t proc_nr; int ipc_to_m, kcalls; sys_map_t map; ip = &image[i]; /* process' attributes */ DEBUGEXTRA(("initializing %s... ", ip->proc_name)); rp = proc_addr(ip->proc_nr); /* get process pointer */ ip->endpoint = rp->p_endpoint; /* ipc endpoint */ make_zero64(rp->p_cpu_time_left); if(i < NR_TASKS) /* name (tasks only) */ strlcpy(rp->p_name, ip->proc_name, sizeof(rp->p_name)); if(i >= NR_TASKS) { /* Remember this so it can be passed to VM */ multiboot_module_t *mb_mod = &kinfo.module_list[i - NR_TASKS]; ip->start_addr = mb_mod->mod_start; ip->len = mb_mod->mod_end - mb_mod->mod_start; } reset_proc_accounting(rp); /* See if this process is immediately schedulable. * In that case, set its privileges now and allow it to run. * Only kernel tasks and the root system process get to run immediately. * All the other system processes are inhibited from running by the * RTS_NO_PRIV flag. They can only be scheduled once the root system * process has set their privileges. */ proc_nr = proc_nr(rp); schedulable_proc = (iskerneln(proc_nr) || isrootsysn(proc_nr) || proc_nr == VM_PROC_NR); if(schedulable_proc) { /* Assign privilege structure. Force a static privilege id. */ (void) get_priv(rp, static_priv_id(proc_nr)); /* Priviliges for kernel tasks. */ if(proc_nr == VM_PROC_NR) { priv(rp)->s_flags = VM_F; priv(rp)->s_trap_mask = SRV_T; ipc_to_m = SRV_M; kcalls = SRV_KC; priv(rp)->s_sig_mgr = SELF; rp->p_priority = SRV_Q; rp->p_quantum_size_ms = SRV_QT; } else if(iskerneln(proc_nr)) { /* Privilege flags. */ priv(rp)->s_flags = (proc_nr == IDLE ? IDL_F : TSK_F); /* Allowed traps. */ priv(rp)->s_trap_mask = (proc_nr == CLOCK || proc_nr == SYSTEM ? CSK_T : TSK_T); ipc_to_m = TSK_M; /* allowed targets */ kcalls = TSK_KC; /* allowed kernel calls */ } /* Priviliges for the root system process. */ else { assert(isrootsysn(proc_nr)); priv(rp)->s_flags= RSYS_F; /* privilege flags */ priv(rp)->s_trap_mask= SRV_T; /* allowed traps */ ipc_to_m = SRV_M; /* allowed targets */ kcalls = SRV_KC; /* allowed kernel calls */ priv(rp)->s_sig_mgr = SRV_SM; /* signal manager */ rp->p_priority = SRV_Q; /* priority queue */ rp->p_quantum_size_ms = SRV_QT; /* quantum size */ } /* Fill in target mask. */ memset(&map, 0, sizeof(map)); if (ipc_to_m == ALL_M) { for(j = 0; j < NR_SYS_PROCS; j++) set_sys_bit(map, j); } fill_sendto_mask(rp, &map); /* Fill in kernel call mask. */ for(j = 0; j < SYS_CALL_MASK_SIZE; j++) { priv(rp)->s_k_call_mask[j] = (kcalls == NO_C ? 0 : (~0)); } } else { /* Don't let the process run for now. */ RTS_SET(rp, RTS_NO_PRIV | RTS_NO_QUANTUM); } /* Arch-specific state initialization. */ arch_boot_proc(ip, rp); /* scheduling functions depend on proc_ptr pointing somewhere. */ if(!get_cpulocal_var(proc_ptr)) get_cpulocal_var(proc_ptr) = rp; /* Process isn't scheduled until VM has set up a pagetable for it. */ if(rp->p_nr != VM_PROC_NR && rp->p_nr >= 0) { rp->p_rts_flags |= RTS_VMINHIBIT; rp->p_rts_flags |= RTS_BOOTINHIBIT; } rp->p_rts_flags |= RTS_PROC_STOP; rp->p_rts_flags &= ~RTS_SLOT_FREE; DEBUGEXTRA(("done\n")); } /* update boot procs info for VM */ memcpy(kinfo.boot_procs, image, sizeof(kinfo.boot_procs)); #define IPCNAME(n) { \ assert((n) >= 0 && (n) <= IPCNO_HIGHEST); \ assert(!ipc_call_names[n]); \ ipc_call_names[n] = #n; \ } arch_post_init(); IPCNAME(SEND); IPCNAME(RECEIVE); IPCNAME(SENDREC); IPCNAME(NOTIFY); IPCNAME(SENDNB); IPCNAME(SENDA); /* System and processes initialization */ memory_init(); DEBUGEXTRA(("system_init()... ")); system_init(); DEBUGEXTRA(("done\n")); /* The bootstrap phase is over, so we can add the physical * memory used for it to the free list. */ add_memmap(&kinfo, kinfo.bootstrap_start, kinfo.bootstrap_len); #ifdef CONFIG_SMP if (config_no_apic) { BOOT_VERBOSE(printf("APIC disabled, disables SMP, using legacy PIC\n")); smp_single_cpu_fallback(); } else if (config_no_smp) { BOOT_VERBOSE(printf("SMP disabled, using legacy PIC\n")); smp_single_cpu_fallback(); } else { smp_init(); /* * if smp_init() returns it means that it failed and we try to finish * single CPU booting */ bsp_finish_booting(); } #else /* * if configured for a single CPU, we are already on the kernel stack which we * are going to use everytime we execute kernel code. We finish booting and we * never return here */ bsp_finish_booting(); #endif NOT_REACHABLE; }
void bsp_finish_booting(void) { int i; #if SPROFILE sprofiling = 0; /* we're not profiling until instructed to */ #endif /* SPROFILE */ cprof_procs_no = 0; /* init nr of hash table slots used */ cpu_identify(); vm_running = 0; krandom.random_sources = RANDOM_SOURCES; krandom.random_elements = RANDOM_ELEMENTS; /* MINIX is now ready. All boot image processes are on the ready queue. * Return to the assembly code to start running the current process. */ /* it should point somewhere */ get_cpulocal_var(bill_ptr) = get_cpulocal_var_ptr(idle_proc); get_cpulocal_var(proc_ptr) = get_cpulocal_var_ptr(idle_proc); announce(); /* print MINIX startup banner */ /* * we have access to the cpu local run queue, only now schedule the processes. * We ignore the slots for the former kernel tasks */ for (i=0; i < NR_BOOT_PROCS - NR_TASKS; i++) { RTS_UNSET(proc_addr(i), RTS_PROC_STOP); } /* * enable timer interrupts and clock task on the boot CPU */ if (boot_cpu_init_timer(system_hz)) { panic("FATAL : failed to initialize timer interrupts, " "cannot continue without any clock source!"); } fpu_init(); /* Warnings for sanity checks that take time. These warnings are printed * so it's a clear warning no full release should be done with them * enabled. */ #if DEBUG_SCHED_CHECK FIXME("DEBUG_SCHED_CHECK enabled"); #endif #if DEBUG_VMASSERT FIXME("DEBUG_VMASSERT enabled"); #endif #if DEBUG_PROC_CHECK FIXME("PROC check enabled"); #endif DEBUGEXTRA(("cycles_accounting_init()... ")); cycles_accounting_init(); DEBUGEXTRA(("done\n")); #ifdef CONFIG_SMP cpu_set_flag(bsp_cpu_id, CPU_IS_READY); machine.processors_count = ncpus; machine.bsp_id = bsp_cpu_id; #else machine.processors_count = 1; machine.bsp_id = 0; #endif /* Kernel may no longer use bits of memory as VM will be running soon */ kernel_may_alloc = 0; switch_to_user(); NOT_REACHABLE; }
/* * The boot processos timer interrupt handler. In addition to non-boot cpus it * keeps real time and notifies the clock task if need be */ PUBLIC int timer_int_handler(void) { /* Update user and system accounting times. Charge the current process * for user time. If the current process is not billable, that is, if a * non-user process is running, charge the billable process for system * time as well. Thus the unbillable process' user time is the billable * user's system time. */ struct proc * p, * billp; /* FIXME watchdog for slave cpus! */ #ifdef CONFIG_WATCHDOG /* * we need to know whether local timer ticks are happening or whether * the kernel is locked up. We don't care about overflows as we only * need to know that it's still ticking or not */ watchdog_local_timer_ticks++; #endif if (cpu_is_bsp(cpuid)) realtime++; /* Update user and system accounting times. Charge the current process * for user time. If the current process is not billable, that is, if a * non-user process is running, charge the billable process for system * time as well. Thus the unbillable process' user time is the billable * user's system time. */ p = get_cpulocal_var(proc_ptr); billp = get_cpulocal_var(bill_ptr); p->p_user_time++; if (! (priv(p)->s_flags & BILLABLE)) { billp->p_sys_time++; } /* Decrement virtual timers, if applicable. We decrement both the * virtual and the profile timer of the current process, and if the * current process is not billable, the timer of the billed process as * well. If any of the timers expire, do_clocktick() will send out * signals. */ if ((p->p_misc_flags & MF_VIRT_TIMER)){ p->p_virt_left--; } if ((p->p_misc_flags & MF_PROF_TIMER)){ p->p_prof_left--; } if (! (priv(p)->s_flags & BILLABLE) && (billp->p_misc_flags & MF_PROF_TIMER)){ billp->p_prof_left--; } /* * Check if a process-virtual timer expired. Check current process, but * also bill_ptr - one process's user time is another's system time, and * the profile timer decreases for both! */ vtimer_check(p); if (p != billp) vtimer_check(billp); /* Update load average. */ load_update(); if (cpu_is_bsp(cpuid)) { /* if a timer expired, notify the clock task */ if ((next_timeout <= realtime)) { tmrs_exptimers(&clock_timers, realtime, NULL); next_timeout = (clock_timers == NULL) ? TMR_NEVER : clock_timers->tmr_exp_time; } if (do_serial_debug) do_ser_debug(); } return(1); /* reenable interrupts */ }
/*===========================================================================* * exception * *===========================================================================*/ PUBLIC void exception_handler(int is_nested, struct exception_frame * frame) { /* An exception or unexpected interrupt has occurred. */ register struct ex_s *ep; struct proc *saved_proc; /* Save proc_ptr, because it may be changed by debug statements. */ saved_proc = get_cpulocal_var(proc_ptr); ep = &ex_data[frame->vector]; if (frame->vector == 2) { /* spurious NMI on some machines */ printf("got spurious NMI\n"); return; } /* * handle special cases for nested problems as they might be tricky or filter * them out quickly if the traps are not nested */ if (is_nested) { /* * if a problem occured while copying a message from userspace because * of a wrong pointer supplied by userland, handle it the only way we * can handle it ... */ if (((void*)frame->eip >= (void*)copy_msg_to_user && (void*)frame->eip <= (void*)__copy_msg_to_user_end) || ((void*)frame->eip >= (void*)copy_msg_from_user && (void*)frame->eip <= (void*)__copy_msg_from_user_end)) { switch(frame->vector) { /* these error are expected */ case PAGE_FAULT_VECTOR: case PROTECTION_VECTOR: frame->eip = (reg_t) __user_copy_msg_pointer_failure; return; default: panic("Copy involving a user pointer failed unexpectedly!"); } } /* Pass any error resulting from restoring FPU state, as a FPU * exception to the process. */ if (((void*)frame->eip >= (void*)fxrstor && (void *)frame->eip <= (void*)__fxrstor_end) || ((void*)frame->eip >= (void*)frstor && (void *)frame->eip <= (void*)__frstor_end)) { frame->eip = (reg_t) __frstor_failure; return; } } if(frame->vector == PAGE_FAULT_VECTOR) { pagefault(saved_proc, frame, is_nested); return; } /* If an exception occurs while running a process, the is_nested variable * will be zero. Exceptions in interrupt handlers or system traps will make * is_nested non-zero. */ if (is_nested == 0 && ! iskernelp(saved_proc)) { #if 0 { printf( "vec_nr= %d, trap_errno= 0x%lx, eip= 0x%lx, cs= 0x%x, eflags= 0x%lx\n", frame->vector, (unsigned long)frame->errcode, (unsigned long)frame->eip, frame->cs, (unsigned long)frame->eflags); printseg("cs: ", 1, saved_proc, frame->cs); printseg("ds: ", 0, saved_proc, saved_proc->p_reg.ds); if(saved_proc->p_reg.ds != saved_proc->p_reg.ss) { printseg("ss: ", 0, saved_proc, saved_proc->p_reg.ss); } proc_stacktrace(saved_proc); } #endif cause_sig(proc_nr(saved_proc), ep->signum); return; } /* Exception in system code. This is not supposed to happen. */ inkernel_disaster(saved_proc, frame, ep, is_nested); panic("return from inkernel_disaster"); }