int do_cpuvar(struct proc *caller_ptr, message *m_ptr){ char *p_pi_ptr = m_ptr->m1_p1; int i; struct proc **queueHeadPtr = NULL; struct proc qh_send[NR_SCHED_QUEUES]; struct proc nullProc; queueHeadPtr = get_cpu_var(0,run_q_head); nullProc.p_priority = -1; for(i=0; i<NR_SCHED_QUEUES; i++){ qh_send[i] = nullProc; } for(i=0; i<NR_SCHED_QUEUES; i++){ if(queueHeadPtr[i]){ qh_send[i] = *queueHeadPtr[i]; } } data_copy_vmcheck(caller_ptr, KERNEL,(vir_bytes) &qh_send, caller_ptr->p_endpoint,(vir_bytes) p_pi_ptr, sizeof(struct proc)*NR_SCHED_QUEUES); return(OK); }
/*===========================================================================* * 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); }
/*===========================================================================* * do_getinfo * *===========================================================================*/ int do_getinfo(struct proc * caller, message * m_ptr) { /* Request system information to be copied to caller's address space. This * call simply copies entire data structures to the caller. */ size_t length; vir_bytes src_vir; int nr_e, nr, r; int wipe_rnd_bin = -1; struct proc *p; /* Set source address and length based on request type. */ switch (m_ptr->I_REQUEST) { case GET_MACHINE: { length = sizeof(struct machine); src_vir = (vir_bytes) &machine; break; } case GET_KINFO: { length = sizeof(struct kinfo); src_vir = (vir_bytes) &kinfo; break; } case GET_LOADINFO: { length = sizeof(struct loadinfo); src_vir = (vir_bytes) &kloadinfo; break; } case GET_CPUINFO: { length = sizeof(cpu_info); src_vir = (vir_bytes) &cpu_info; break; } case GET_HZ: { length = sizeof(system_hz); src_vir = (vir_bytes) &system_hz; break; } case GET_IMAGE: { length = sizeof(struct boot_image) * NR_BOOT_PROCS; src_vir = (vir_bytes) image; break; } case GET_IRQHOOKS: { length = sizeof(struct irq_hook) * NR_IRQ_HOOKS; src_vir = (vir_bytes) irq_hooks; break; } case GET_PROCTAB: { update_idle_time(); length = sizeof(struct proc) * (NR_PROCS + NR_TASKS); src_vir = (vir_bytes) proc; break; } case GET_PRIVTAB: { length = sizeof(struct priv) * (NR_SYS_PROCS); src_vir = (vir_bytes) priv; break; } case GET_PROC: { nr_e = (m_ptr->I_VAL_LEN2_E == SELF) ? caller->p_endpoint : m_ptr->I_VAL_LEN2_E; if(!isokendpt(nr_e, &nr)) return EINVAL; /* validate request */ length = sizeof(struct proc); src_vir = (vir_bytes) proc_addr(nr); break; } case GET_PRIV: { nr_e = (m_ptr->I_VAL_LEN2_E == SELF) ? caller->p_endpoint : m_ptr->I_VAL_LEN2_E; if(!isokendpt(nr_e, &nr)) return EINVAL; /* validate request */ length = sizeof(struct priv); src_vir = (vir_bytes) priv_addr(nr_to_id(nr)); break; } case GET_REGS: { nr_e = (m_ptr->I_VAL_LEN2_E == SELF) ? caller->p_endpoint : m_ptr->I_VAL_LEN2_E; if(!isokendpt(nr_e, &nr)) return EINVAL; /* validate request */ p = proc_addr(nr); length = sizeof(p->p_reg); src_vir = (vir_bytes) &p->p_reg; break; } case GET_WHOAMI: { int len; /* GET_WHOAMI uses m3 and only uses the message contents for info. */ m_ptr->GIWHO_EP = caller->p_endpoint; len = MIN(sizeof(m_ptr->GIWHO_NAME), sizeof(caller->p_name))-1; strncpy(m_ptr->GIWHO_NAME, caller->p_name, len); m_ptr->GIWHO_NAME[len] = '\0'; m_ptr->GIWHO_PRIVFLAGS = priv(caller)->s_flags; return OK; } case GET_MONPARAMS: { src_vir = (vir_bytes) params_buffer; length = sizeof(params_buffer); break; } case GET_RANDOMNESS: { static struct k_randomness copy; /* copy to keep counters */ int i; copy = krandom; for (i= 0; i<RANDOM_SOURCES; i++) { krandom.bin[i].r_size = 0; /* invalidate random data */ krandom.bin[i].r_next = 0; } length = sizeof(copy); src_vir = (vir_bytes) © break; } case GET_RANDOMNESS_BIN: { int bin = m_ptr->I_VAL_LEN2_E; if(bin < 0 || bin >= RANDOM_SOURCES) { printf("SYSTEM: GET_RANDOMNESS_BIN: %d out of range\n", bin); return EINVAL; } if(krandom.bin[bin].r_size < RANDOM_ELEMENTS) return ENOENT; length = sizeof(krandom.bin[bin]); src_vir = (vir_bytes) &krandom.bin[bin]; wipe_rnd_bin = bin; break; } case GET_KMESSAGES: { length = sizeof(struct kmessages); src_vir = (vir_bytes) &kmess; break; } case GET_IRQACTIDS: { length = sizeof(irq_actids); src_vir = (vir_bytes) irq_actids; break; } case GET_IDLETSC: { struct proc * idl; update_idle_time(); idl = proc_addr(IDLE); length = sizeof(idl->p_cycles); src_vir = (vir_bytes) &idl->p_cycles; break; } default: printf("do_getinfo: invalid request %d\n", m_ptr->I_REQUEST); return(EINVAL); } /* Try to make the actual copy for the requested data. */ if (m_ptr->I_VAL_LEN > 0 && length > m_ptr->I_VAL_LEN) return (E2BIG); r = data_copy_vmcheck(caller, KERNEL, src_vir, caller->p_endpoint, (vir_bytes) m_ptr->I_VAL_PTR, length); if(r != OK) return r; if(wipe_rnd_bin >= 0 && wipe_rnd_bin < RANDOM_SOURCES) { krandom.bin[wipe_rnd_bin].r_size = 0; krandom.bin[wipe_rnd_bin].r_next = 0; } return(OK); }
/*===========================================================================* * do_vumap * *===========================================================================*/ int do_vumap(struct proc *caller, message *m_ptr) { /* Map a vector of grants or local virtual addresses to physical addresses. * Designed to be used by drivers to perform an efficient lookup of physical * addresses for the purpose of direct DMA from/to a remote process. */ endpoint_t endpt, source, granter; struct proc *procp; struct vumap_vir vvec[MAPVEC_NR]; struct vumap_phys pvec[MAPVEC_NR]; vir_bytes vaddr, paddr, vir_addr; phys_bytes phys_addr; int i, r, proc_nr, vcount, pcount, pmax, access; size_t size, chunk, offset; endpt = caller->p_endpoint; /* Retrieve and check input parameters. */ source = m_ptr->VUMAP_ENDPT; vaddr = (vir_bytes) m_ptr->VUMAP_VADDR; vcount = m_ptr->VUMAP_VCOUNT; offset = m_ptr->VUMAP_OFFSET; access = m_ptr->VUMAP_ACCESS; paddr = (vir_bytes) m_ptr->VUMAP_PADDR; pmax = m_ptr->VUMAP_PMAX; if (vcount <= 0 || pmax <= 0) return EINVAL; if (vcount > MAPVEC_NR) vcount = MAPVEC_NR; if (pmax > MAPVEC_NR) pmax = MAPVEC_NR; /* Convert access to safecopy access flags. */ switch (access) { case VUA_READ: access = CPF_READ; break; case VUA_WRITE: access = CPF_WRITE; break; case VUA_READ|VUA_WRITE: access = CPF_READ|CPF_WRITE; break; default: return EINVAL; } /* Copy in the vector of virtual addresses. */ size = vcount * sizeof(vvec[0]); if (data_copy(endpt, vaddr, KERNEL, (vir_bytes) vvec, size) != OK) return EFAULT; pcount = 0; /* Go through the input entries, one at a time. Stop early in case the output * vector has filled up. */ for (i = 0; i < vcount && pcount < pmax; i++) { size = vvec[i].vv_size; if (size <= offset) return EINVAL; size -= offset; if (source != SELF) { r = verify_grant(source, endpt, vvec[i].vv_grant, size, access, offset, &vir_addr, &granter); if (r != OK) return r; } else { vir_addr = vvec[i].vv_addr + offset; granter = endpt; } okendpt(granter, &proc_nr); procp = proc_addr(proc_nr); /* Each virtual range is made up of one or more physical ranges. */ while (size > 0 && pcount < pmax) { chunk = vm_lookup_range(procp, vir_addr, &phys_addr, size); if (!chunk) { /* Try to get the memory allocated, unless the memory * is supposed to be there to be read from. */ if (access & CPF_READ) return EFAULT; /* This call may suspend the current call, or return an * error for a previous invocation. */ return vm_check_range(caller, procp, vir_addr, size); } pvec[pcount].vp_addr = phys_addr; pvec[pcount].vp_size = chunk; pcount++; vir_addr += chunk; size -= chunk; } offset = 0; } /* Copy out the resulting vector of physical addresses. */ assert(pcount > 0); size = pcount * sizeof(pvec[0]); r = data_copy_vmcheck(caller, KERNEL, (vir_bytes) pvec, endpt, paddr, size); if (r == OK) m_ptr->VUMAP_PCOUNT = pcount; return r; }
/*===========================================================================* * 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); }