static void print_proc_depends(struct proc *pp, const int level) { struct proc *depproc = NULL; endpoint_t dep; #define COL { int i; for(i = 0; i < level; i++) printf("> "); } if(level >= NR_PROCS) { printf("loop??\n"); return; } COL print_proc(pp); COL proc_stacktrace(pp); dep = P_BLOCKEDON(pp); if(dep != NONE && dep != ANY) { int procno; if(isokendpt(dep, &procno)) { depproc = proc_addr(procno); if(isemptyp(depproc)) depproc = NULL; } if (depproc) print_proc_depends(depproc, level+1); } }
void pagefault(struct proc *pr, int trap_errno) { int s; vir_bytes ph; u32_t pte; if(pagefault_count != 1) minix_panic("recursive pagefault", pagefault_count); /* Don't schedule this process until pagefault is handled. */ if(RTS_ISSET(pr, PAGEFAULT)) minix_panic("PAGEFAULT set", pr->p_endpoint); RTS_LOCK_SET(pr, PAGEFAULT); if(pr->p_endpoint <= INIT_PROC_NR) { /* Page fault we can't / don't want to * handle. */ kprintf("pagefault for process %d ('%s'), pc = 0x%x\n", pr->p_endpoint, pr->p_name, pr->p_reg.pc); proc_stacktrace(pr); minix_panic("page fault in system process", pr->p_endpoint); return; } /* Save pagefault details, suspend process, * add process to pagefault chain, * and tell VM there is a pagefault to be * handled. */ pr->p_pagefault.pf_virtual = pagefault_cr2; pr->p_pagefault.pf_flags = trap_errno; pr->p_nextpagefault = pagefaults; pagefaults = pr; lock_notify(HARDWARE, VM_PROC_NR); pagefault_count = 0; #if 0 kprintf("pagefault for process %d ('%s'), pc = 0x%x\n", pr->p_endpoint, pr->p_name, pr->p_reg.pc); proc_stacktrace(pr); #endif return; }
PRIVATE void inkernel_disaster(struct proc *saved_proc, struct exception_frame * frame, struct ex_s *ep, int is_nested) { #if USE_SYSDEBUG if(ep) { if (ep->msg == NULL) printf("\nIntel-reserved exception %d\n", frame->vector); else printf("\n%s\n", ep->msg); } printf("cpu %d is_nested = %d ", cpuid, is_nested); printf("vec_nr= %d, trap_errno= 0x%x, eip= 0x%x, " "cs= 0x%x, eflags= 0x%x trap_esp 0x%08x\n", frame->vector, frame->errcode, frame->eip, frame->cs, frame->eflags, frame); printf("KERNEL registers :\n"); #define REG(n) (((u32_t *)frame)[-n]) printf( "\t%%eax 0x%08x %%ebx 0x%08x %%ecx 0x%08x %%edx 0x%08x\n" "\t%%esp 0x%08x %%ebp 0x%08x %%esi 0x%08x %%edi 0x%08x\n", REG(1), REG(2), REG(3), REG(4), REG(5), REG(6), REG(7), REG(8)); { reg_t k_ebp = REG(6); printf("KERNEL stacktrace, starting with ebp = 0x%lx:\n", k_ebp); proc_stacktrace_execute(proc_addr(SYSTEM), k_ebp, frame->eip); } printseg("ker cs: ", 1, NULL, frame->cs); printseg("ker ds: ", 0, NULL, DS_SELECTOR); if (saved_proc) { printf("scheduled was: process %d (%s), ", saved_proc->p_endpoint, saved_proc->p_name); printf("pc = %u:0x%x\n", (unsigned) saved_proc->p_reg.cs, (unsigned) saved_proc->p_reg.pc); proc_stacktrace(saved_proc); panic("Unhandled kernel exception"); } /* in an early stage of boot process we don't have processes yet */ panic("exception in kernel while booting, no saved_proc yet"); #endif /* USE_SYSDEBUG */ }
/*===========================================================================* * do_sysctl * *===========================================================================*/ PUBLIC int do_sysctl(struct proc * caller, message * m_ptr) { vir_bytes len, buf; static char mybuf[DIAG_BUFSIZE]; int s, i, proc_nr; switch (m_ptr->SYSCTL_CODE) { case SYSCTL_CODE_DIAG: buf = (vir_bytes) m_ptr->SYSCTL_ARG1; len = (vir_bytes) m_ptr->SYSCTL_ARG2; if(len < 1 || len > DIAG_BUFSIZE) { printf("do_sysctl: diag for %d: len %d out of range\n", caller->p_endpoint, len); return EINVAL; } if((s=data_copy_vmcheck(caller, caller->p_endpoint, buf, KERNEL, (vir_bytes) mybuf, len)) != OK) { printf("do_sysctl: diag for %d: len %d: copy failed: %d\n", caller->p_endpoint, len, s); return s; } for(i = 0; i < len; i++) kputc(mybuf[i]); kputc(END_OF_KMESS); return OK; case SYSCTL_CODE_STACKTRACE: if(!isokendpt(m_ptr->SYSCTL_ARG2, &proc_nr)) return EINVAL; proc_stacktrace(proc_addr(proc_nr)); proc_dump_regs(proc_addr(proc_nr)); return OK; default: printf("do_sysctl: invalid request %d\n", m_ptr->SYSCTL_CODE); return(EINVAL); } panic("do_sysctl: can't happen"); return(OK); }
/*===========================================================================* * 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); }
/*==========================================================================* * do_umap_remote * *==========================================================================*/ int do_umap_remote(struct proc * caller, message * m_ptr) { /* Map virtual address to physical, for non-kernel processes. */ int seg_type = m_ptr->CP_SRC_SPACE & SEGMENT_TYPE; int seg_index = m_ptr->CP_SRC_SPACE & SEGMENT_INDEX; vir_bytes offset = m_ptr->CP_SRC_ADDR; int count = m_ptr->CP_NR_BYTES; int endpt = (int) m_ptr->CP_SRC_ENDPT; endpoint_t grantee = (endpoint_t) m_ptr->CP_DST_ENDPT; int proc_nr, proc_nr_grantee; int naughty = 0; phys_bytes phys_addr = 0, lin_addr = 0; struct proc *targetpr; /* Verify process number. */ if (endpt == SELF) proc_nr = _ENDPOINT_P(caller->p_endpoint); else if (! isokendpt(endpt, &proc_nr)) return(EINVAL); targetpr = proc_addr(proc_nr); /* Verify grantee endpoint */ if (grantee == SELF) { grantee = caller->p_endpoint; } else if (grantee == NONE || grantee == ANY || seg_index != MEM_GRANT || !isokendpt(grantee, &proc_nr_grantee)) { return EINVAL; } /* See which mapping should be made. */ switch(seg_type) { case LOCAL_SEG: phys_addr = lin_addr = umap_local(targetpr, seg_index, offset, count); if(!lin_addr) return EFAULT; naughty = 1; break; case LOCAL_VM_SEG: if(seg_index == MEM_GRANT) { vir_bytes newoffset; endpoint_t newep; int new_proc_nr; cp_grant_id_t grant = (cp_grant_id_t) offset; if(verify_grant(targetpr->p_endpoint, grantee, grant, count, 0, 0, &newoffset, &newep) != OK) { printf("SYSTEM: do_umap: verify_grant in %s, grant %d, bytes 0x%lx, failed, caller %s\n", targetpr->p_name, offset, count, caller->p_name); proc_stacktrace(caller); return EFAULT; } if(!isokendpt(newep, &new_proc_nr)) { printf("SYSTEM: do_umap: isokendpt failed\n"); return EFAULT; } /* New lookup. */ offset = newoffset; targetpr = proc_addr(new_proc_nr); seg_index = D; } if(seg_index == T || seg_index == D || seg_index == S) { phys_addr = lin_addr = umap_local(targetpr, seg_index, offset, count); } else { printf("SYSTEM: bogus seg type 0x%lx\n", seg_index); return EFAULT; } if(!lin_addr) { printf("SYSTEM:do_umap: umap_local failed\n"); return EFAULT; } if(vm_lookup(targetpr, lin_addr, &phys_addr, NULL) != OK) { printf("SYSTEM:do_umap: vm_lookup failed\n"); return EFAULT; } if(phys_addr == 0) panic("vm_lookup returned zero physical address"); break; default: printf("umap: peculiar type\n"); return EINVAL; } if(vm_running && vm_lookup_range(targetpr, lin_addr, NULL, count) != count) { printf("SYSTEM:do_umap: not contiguous\n"); return EFAULT; } m_ptr->CP_DST_ADDR = phys_addr; if(naughty || phys_addr == 0) { printf("kernel: umap 0x%x done by %d / %s, pc 0x%lx, 0x%lx -> 0x%lx\n", seg_type, caller->p_endpoint, caller->p_name, caller->p_reg.pc, offset, phys_addr); printf("caller stack: "); proc_stacktrace(caller); } return (phys_addr == 0) ? EFAULT: OK; }
/*===========================================================================* * 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; }
/*===========================================================================* * do_update * *===========================================================================*/ PUBLIC 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; /* 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; } /* 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", ptproc->p_endpoint); #endif /* 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(&ptproc, src_rp, dst_rp); /* Fix segments. */ alloc_segments(src_rp); alloc_segments(dst_rp); prot_init(); #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", ptproc->p_endpoint); #endif return OK; }
PRIVATE void pagefault( struct proc *pr, struct exception_frame * frame, int is_nested) { int in_physcopy = 0; reg_t pagefaultcr2; message m_pagefault; int err; assert(frame); pagefaultcr2 = read_cr2(); #if 0 printf("kernel: pagefault in pr %d, addr 0x%lx, his cr3 0x%lx, actual cr3 0x%lx\n", pr->p_endpoint, pagefaultcr2, pr->p_seg.p_cr3, read_cr3()); #endif if(pr->p_seg.p_cr3) { assert(pr->p_seg.p_cr3 == read_cr3()); } in_physcopy = (frame->eip > (vir_bytes) phys_copy) && (frame->eip < (vir_bytes) phys_copy_fault); if((is_nested || iskernelp(pr)) && catch_pagefaults && in_physcopy) { #if 0 printf("pf caught! addr 0x%lx\n", pagefaultcr2); #endif if (is_nested) { frame->eip = (reg_t) phys_copy_fault_in_kernel; } else { pr->p_reg.pc = (reg_t) phys_copy_fault; pr->p_reg.retreg = pagefaultcr2; } return; } if(is_nested) { panic("pagefault in kernel at pc 0x%lx address 0x%lx", frame->eip, pagefaultcr2); } /* System processes that don't have their own page table can't * have page faults. VM does have its own page table but also * can't have page faults (because VM has to handle them). */ if((pr->p_endpoint <= INIT_PROC_NR && !(pr->p_misc_flags & MF_FULLVM)) || pr->p_endpoint == VM_PROC_NR) { /* Page fault we can't / don't want to * handle. */ printf("pagefault for process %d ('%s'), pc = 0x%x, addr = 0x%x, flags = 0x%x, is_nested %d\n", pr->p_endpoint, pr->p_name, pr->p_reg.pc, pagefaultcr2, frame->errcode, is_nested); proc_stacktrace(pr); printf("pc of pagefault: 0x%lx\n", frame->eip); panic("page fault in system process: %d", pr->p_endpoint); return; } /* Don't schedule this process until pagefault is handled. */ assert(pr->p_seg.p_cr3 == read_cr3()); assert(!RTS_ISSET(pr, RTS_PAGEFAULT)); RTS_SET(pr, RTS_PAGEFAULT); /* tell Vm about the pagefault */ m_pagefault.m_source = pr->p_endpoint; m_pagefault.m_type = VM_PAGEFAULT; m_pagefault.VPF_ADDR = pagefaultcr2; m_pagefault.VPF_FLAGS = frame->errcode; if ((err = mini_send(pr, VM_PROC_NR, &m_pagefault, FROM_KERNEL))) { panic("WARNING: pagefault: mini_send returned %d\n", err); } return; }
/*===========================================================================* * exception * *===========================================================================*/ PUBLIC void exception_handler(int is_nested, struct exception_frame * frame) { /* An exception or unexpected interrupt has occurred. */ struct ex_s { char *msg; int signum; int minprocessor; }; static struct ex_s ex_data[] = { { "Divide error", SIGFPE, 86 }, { "Debug exception", SIGTRAP, 86 }, { "Nonmaskable interrupt", SIGBUS, 86 }, { "Breakpoint", SIGEMT, 86 }, { "Overflow", SIGFPE, 86 }, { "Bounds check", SIGFPE, 186 }, { "Invalid opcode", SIGILL, 186 }, { "Coprocessor not available", SIGFPE, 186 }, { "Double fault", SIGBUS, 286 }, { "Coprocessor segment overrun", SIGSEGV, 286 }, { "Invalid TSS", SIGSEGV, 286 }, { "Segment not present", SIGSEGV, 286 }, { "Stack exception", SIGSEGV, 286 }, /* STACK_FAULT already used */ { "General protection", SIGSEGV, 286 }, { "Page fault", SIGSEGV, 386 }, /* not close */ { NULL, SIGILL, 0 }, /* probably software trap */ { "Coprocessor error", SIGFPE, 386 }, { "Alignment check", SIGBUS, 386 }, { "Machine check", SIGBUS, 386 }, { "SIMD exception", SIGFPE, 386 }, }; register struct ex_s *ep; struct proc *saved_proc; /* Save proc_ptr, because it may be changed by debug statements. */ saved_proc = 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!"); } } } 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. */ if (ep->msg == NULL || machine.processor < ep->minprocessor) printf("\nIntel-reserved exception %d\n", frame->vector); else printf("\n%s\n", ep->msg); printf("is_nested = %d ", is_nested); printf("vec_nr= %d, trap_errno= 0x%x, eip= 0x%x, " "cs= 0x%x, eflags= 0x%x trap_esp 0x%08x\n", frame->vector, frame->errcode, frame->eip, frame->cs, frame->eflags, frame); printf("KERNEL registers :\n"); printf( "\t%%eax 0x%08x %%ebx 0x%08x %%ecx 0x%08x %%edx 0x%08x\n" "\t%%esp 0x%08x %%ebp 0x%08x %%esi 0x%08x %%edi 0x%08x\n", ((u32_t *)frame)[-1], ((u32_t *)frame)[-2], ((u32_t *)frame)[-3], ((u32_t *)frame)[-4], ((u32_t *)frame)[-5], ((u32_t *)frame)[-6], ((u32_t *)frame)[-7], ((u32_t *)frame)[-8] ); printseg("ker cs: ", 1, NULL, frame->cs); printseg("ker ds: ", 0, NULL, DS_SELECTOR); /* TODO should we enable this only when compiled for some debug mode? */ if (saved_proc) { printf("scheduled was: process %d (%s), ", proc_nr(saved_proc), saved_proc->p_name); printf("pc = %u:0x%x\n", (unsigned) saved_proc->p_reg.cs, (unsigned) saved_proc->p_reg.pc); proc_stacktrace(saved_proc); panic("Unhandled kernel exception"); } else { /* in an early stage of boot process we don't have processes yet */ panic("exception in kernel while booting"); } }
/*===========================================================================* * 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; }
/*===========================================================================* * 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"); }
/*===========================================================================* * do_sigsend * *===========================================================================*/ int do_sigsend(struct proc * caller, message * m_ptr) { /* Handle sys_sigsend, POSIX-style signal handling. */ struct sigmsg smsg; register struct proc *rp; struct sigcontext sc, *scp; struct sigframe fr, *frp; int proc_nr, r; if (!isokendpt(m_ptr->SIG_ENDPT, &proc_nr)) return(EINVAL); if (iskerneln(proc_nr)) return(EPERM); rp = proc_addr(proc_nr); /* Get the sigmsg structure into our address space. */ if((r=data_copy_vmcheck(caller, caller->p_endpoint, (vir_bytes) m_ptr->SIG_CTXT_PTR, KERNEL, (vir_bytes) &smsg, (phys_bytes) sizeof(struct sigmsg))) != OK) return r; /* Compute the user stack pointer where sigcontext will be stored. */ smsg.sm_stkptr = arch_get_sp(rp); scp = (struct sigcontext *) smsg.sm_stkptr - 1; /* Copy the registers to the sigcontext structure. */ memcpy(&sc.sc_regs, (char *) &rp->p_reg, sizeof(sigregs)); #if defined(__i386__) sc.trap_style = rp->p_seg.p_kern_trap_style; if(sc.trap_style == KTS_NONE) { printf("do_sigsend: sigsend an unsaved process\n"); return EINVAL; } if(proc_used_fpu(rp)) { /* save the FPU context before saving it to the sig context */ save_fpu(rp); memcpy(&sc.sc_fpu_state, rp->p_seg.fpu_state, FPU_XFP_SIZE); } #endif /* Finish the sigcontext initialization. */ sc.sc_mask = smsg.sm_mask; sc.sc_flags = rp->p_misc_flags & MF_FPU_INITIALIZED; /* Copy the sigcontext structure to the user's stack. */ if((r=data_copy_vmcheck(caller, KERNEL, (vir_bytes) &sc, m_ptr->SIG_ENDPT, (vir_bytes) scp, (vir_bytes) sizeof(struct sigcontext))) != OK) return r; /* Initialize the sigframe structure. */ frp = (struct sigframe *) scp - 1; fr.sf_scpcopy = scp; fr.sf_retadr2= (void (*)()) rp->p_reg.pc; fr.sf_fp = rp->p_reg.fp; rp->p_reg.fp = (reg_t) &frp->sf_fp; fr.sf_scp = scp; fpu_sigcontext(rp, &fr, &sc); fr.sf_signo = smsg.sm_signo; fr.sf_retadr = (void (*)()) smsg.sm_sigreturn; #if defined(__arm__) /* use the ARM link register to set the return address from the signal * handler */ rp->p_reg.lr = (reg_t) fr.sf_retadr; if(rp->p_reg.lr & 1) { printf("sigsend: LSB LR makes no sense.\n"); } /* pass signal handler parameters in registers */ rp->p_reg.retreg = (reg_t) fr.sf_signo; rp->p_reg.r1 = (reg_t) fr.sf_code; rp->p_reg.r2 = (reg_t) fr.sf_scp; rp->p_misc_flags |= MF_CONTEXT_SET; #endif /* Copy the sigframe structure to the user's stack. */ if((r=data_copy_vmcheck(caller, KERNEL, (vir_bytes) &fr, m_ptr->SIG_ENDPT, (vir_bytes) frp, (vir_bytes) sizeof(struct sigframe))) != OK) return r; /* Reset user registers to execute the signal handler. */ rp->p_reg.sp = (reg_t) frp; rp->p_reg.pc = (reg_t) smsg.sm_sighandler; /* Signal handler should get clean FPU. */ rp->p_misc_flags &= ~MF_FPU_INITIALIZED; if(!RTS_ISSET(rp, RTS_PROC_STOP)) { printf("system: warning: sigsend a running process\n"); printf("caller stack: "); proc_stacktrace(caller); } return(OK); }
/*===========================================================================* * do_sigsend * *===========================================================================*/ PUBLIC int do_sigsend(struct proc * caller, message * m_ptr) { /* Handle sys_sigsend, POSIX-style signal handling. */ struct sigmsg smsg; register struct proc *rp; struct sigcontext sc, *scp; struct sigframe fr, *frp; int proc_nr, r; if (!isokendpt(m_ptr->SIG_ENDPT, &proc_nr)) return(EINVAL); if (iskerneln(proc_nr)) return(EPERM); rp = proc_addr(proc_nr); /* Get the sigmsg structure into our address space. */ if((r=data_copy_vmcheck(caller, caller->p_endpoint, (vir_bytes) m_ptr->SIG_CTXT_PTR, KERNEL, (vir_bytes) &smsg, (phys_bytes) sizeof(struct sigmsg))) != OK) return r; /* Compute the user stack pointer where sigcontext will be stored. */ scp = (struct sigcontext *) smsg.sm_stkptr - 1; /* Copy the registers to the sigcontext structure. */ memcpy(&sc.sc_regs, (char *) &rp->p_reg, sizeof(sigregs)); #if (_MINIX_CHIP == _CHIP_INTEL) if(proc_used_fpu(rp)) { /* save the FPU context before saving it to the sig context */ save_fpu(rp); memcpy(&sc.sc_fpu_state, rp->p_fpu_state.fpu_save_area_p, FPU_XFP_SIZE); } #endif /* Finish the sigcontext initialization. */ sc.sc_mask = smsg.sm_mask; sc.sc_flags = rp->p_misc_flags & MF_FPU_INITIALIZED; /* Copy the sigcontext structure to the user's stack. */ if((r=data_copy_vmcheck(caller, KERNEL, (vir_bytes) &sc, m_ptr->SIG_ENDPT, (vir_bytes) scp, (vir_bytes) sizeof(struct sigcontext))) != OK) return r; /* Initialize the sigframe structure. */ frp = (struct sigframe *) scp - 1; fr.sf_scpcopy = scp; fr.sf_retadr2= (void (*)()) rp->p_reg.pc; fr.sf_fp = rp->p_reg.fp; rp->p_reg.fp = (reg_t) &frp->sf_fp; fr.sf_scp = scp; fpu_sigcontext(rp, &fr, &sc); fr.sf_signo = smsg.sm_signo; fr.sf_retadr = (void (*)()) smsg.sm_sigreturn; /* Copy the sigframe structure to the user's stack. */ if((r=data_copy_vmcheck(caller, KERNEL, (vir_bytes) &fr, m_ptr->SIG_ENDPT, (vir_bytes) frp, (vir_bytes) sizeof(struct sigframe))) != OK) return r; /* Reset user registers to execute the signal handler. */ rp->p_reg.sp = (reg_t) frp; rp->p_reg.pc = (reg_t) smsg.sm_sighandler; /* Signal handler should get clean FPU. */ rp->p_misc_flags &= ~MF_FPU_INITIALIZED; if(!RTS_ISSET(rp, RTS_PROC_STOP)) { printf("system: warning: sigsend a running process\n"); printf("caller stack: "); proc_stacktrace(caller); } return(OK); }