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); } }
static void print_endpoint(endpoint_t ep) { int proc_nr; struct proc *pp = NULL; switch(ep) { case ANY: printf("ANY"); break; case SELF: printf("SELF"); break; case NONE: printf("NONE"); break; default: if(!isokendpt(ep, &proc_nr)) { printf("??? %d\n", ep); } else { pp = proc_addr(proc_nr); if(isemptyp(pp)) { printf("??? empty slot %d\n", proc_nr); } else { print_proc_name(pp); } } break; } }
/*===========================================================================* * memmap_dmp * *===========================================================================*/ PUBLIC void memmap_dmp() { register struct proc *rp; static struct proc *oldrp = proc; int r, n = 0; phys_clicks size; /* First obtain a fresh copy of the current process table. */ if ((r = sys_getproctab(proc)) != OK) { report("IS","warning: couldn't get copy of process table", r); return; } printf("\n-nr/name--- --pc-- --sp-- -----text----- -----data----- ----stack----- --size-\n"); for (rp = oldrp; rp < END_PROC_ADDR; rp++) { if (isemptyp(rp)) continue; if (++n > 23) break; size = rp->p_memmap[T].mem_len + ((rp->p_memmap[S].mem_phys + rp->p_memmap[S].mem_len) - rp->p_memmap[D].mem_phys); printf("%3d %-7.7s%7lx%7lx %4x %4x %4x %4x %4x %4x %4x %4x %4x %5uK\n", proc_nr(rp), rp->p_name, (unsigned long) rp->p_reg.pc, (unsigned long) rp->p_reg.sp, rp->p_memmap[T].mem_vir, rp->p_memmap[T].mem_phys, rp->p_memmap[T].mem_len, rp->p_memmap[D].mem_vir, rp->p_memmap[D].mem_phys, rp->p_memmap[D].mem_len, rp->p_memmap[S].mem_vir, rp->p_memmap[S].mem_phys, rp->p_memmap[S].mem_len, click_to_round_k(size)); } if (rp == END_PROC_ADDR) rp = proc; else printf("--more--\r"); oldrp = rp; }
PUBLIC void ser_dump_proc() { struct proc *pp; for (pp= BEG_PROC_ADDR; pp < END_PROC_ADDR; pp++) { if (isemptyp(pp)) continue; print_proc_recursive(pp); } }
PRIVATE void ser_dump_proc_cpu(void) { struct proc *pp; unsigned cpu; for (cpu = 0; cpu < ncpus; cpu++) { printf("CPU %d processes : \n", cpu); for (pp= BEG_USER_ADDR; pp < END_PROC_ADDR; pp++) { if (isemptyp(pp) || pp->p_cpu != cpu) continue; print_proc(pp); } } }
PRIVATE void ser_dump_segs(void) { struct proc *pp; for (pp= BEG_PROC_ADDR; pp < END_PROC_ADDR; pp++) { if (isemptyp(pp)) continue; printf("%d: %s ep %d\n", proc_nr(pp), pp->p_name, pp->p_endpoint); printseg("cs: ", 1, pp, pp->p_reg.cs); printseg("ds: ", 0, pp, pp->p_reg.ds); if(pp->p_reg.ss != pp->p_reg.ds) { printseg("ss: ", 0, pp, pp->p_reg.ss); } } }
/*===========================================================================* * privileges_dmp * *===========================================================================*/ PUBLIC void privileges_dmp() { register struct proc *rp; static struct proc *oldrp = BEG_PROC_ADDR; register struct priv *sp; static char ipc_to[NR_SYS_PROCS + 1 + NR_SYS_PROCS/8]; int r, i,j, n = 0; /* First obtain a fresh copy of the current process and system table. */ if ((r = sys_getprivtab(priv)) != OK) { report("IS","warning: couldn't get copy of system privileges table", r); return; } if ((r = sys_getproctab(proc)) != OK) { report("IS","warning: couldn't get copy of process table", r); return; } printf("\n--nr-id-name---- -flags- -traps- -ipc_to mask------------------------ \n"); for (rp = oldrp; rp < END_PROC_ADDR; rp++) { if (isemptyp(rp)) continue; if (++n > 23) break; if (proc_nr(rp) == IDLE) printf("(%2d) ", proc_nr(rp)); else if (proc_nr(rp) < 0) printf("[%2d] ", proc_nr(rp)); else printf(" %2d ", proc_nr(rp)); r = -1; for (sp = &priv[0]; sp < &priv[NR_SYS_PROCS]; sp++) if (sp->s_proc_nr == rp->p_nr) { r ++; break; } if (r == -1 && ! (rp->p_rts_flags & SLOT_FREE)) { sp = &priv[USER_PRIV_ID]; } printf("(%02u) %-7.7s %s %s ", sp->s_id, rp->p_name, s_flags_str(sp->s_flags), s_traps_str(sp->s_trap_mask) ); for (i=j=0; i < NR_SYS_PROCS; i++, j++) { ipc_to[j] = get_sys_bit(sp->s_ipc_to, i) ? '1' : '0'; if (i % 8 == 7) ipc_to[++j] = ' '; } ipc_to[j] = '\0'; printf(" %s \n", ipc_to); } if (rp == END_PROC_ADDR) rp = BEG_PROC_ADDR; else printf("--more--\r"); oldrp = rp; }
/*===========================================================================* * sendmask_dmp * *===========================================================================*/ PUBLIC void sendmask_dmp() { register struct proc *rp; static struct proc *oldrp = BEG_PROC_ADDR; int r, i,j, n = 0; /* First obtain a fresh copy of the current process table. */ if ((r = sys_getproctab(proc)) != OK) { report("IS","warning: couldn't get copy of process table", r); return; } printf("\n\n"); printf("Sendmask dump for process table. User processes (*) don't have []."); printf("\n"); printf("The rows of bits indicate to which processes each process may send."); printf("\n\n"); #if DEAD_CODE printf(" "); for (j=proc_nr(BEG_PROC_ADDR); j< INIT_PROC_NR+1; j++) { printf("%3d", j); } printf(" *\n"); for (rp = oldrp; rp < END_PROC_ADDR; rp++) { if (isemptyp(rp)) continue; if (++n > 20) break; printf("%8s ", rp->p_name); if (proc_nr(rp) == IDLE) printf("(%2d) ", proc_nr(rp)); else if (proc_nr(rp) < 0) printf("[%2d] ", proc_nr(rp)); else printf(" %2d ", proc_nr(rp)); for (j=proc_nr(BEG_PROC_ADDR); j<INIT_PROC_NR+2; j++) { if (isallowed(rp->p_sendmask, j)) printf(" 1 "); else printf(" 0 "); } printf("\n"); } if (rp == END_PROC_ADDR) { printf("\n"); rp = BEG_PROC_ADDR; } else printf("--more--\r"); oldrp = rp; #endif }
PUBLIC void proctab_dmp() { /* Proc table dump */ register struct proc *rp; static struct proc *oldrp = BEG_PROC_ADDR; int r, n = 0; phys_clicks text, data, size; /* First obtain a fresh copy of the current process table. */ if ((r = sys_getproctab(proc)) != OK) { report("IS","warning: couldn't get copy of process table", r); return; } printf("\n-nr-----gen---endpoint--name--- -prior-quant- -user---sys----size-rts flags-\n"); for (rp = oldrp; rp < END_PROC_ADDR; rp++) { if (isemptyp(rp)) continue; if (++n > 23) break; text = rp->p_memmap[T].mem_phys; data = rp->p_memmap[D].mem_phys; size = rp->p_memmap[T].mem_len + ((rp->p_memmap[S].mem_phys + rp->p_memmap[S].mem_len) - data); if (proc_nr(rp) == IDLE) printf("(%2d) ", proc_nr(rp)); else if (proc_nr(rp) < 0) printf("[%2d] ", proc_nr(rp)); else printf(" %2d ", proc_nr(rp)); printf(" %5d %10d ", _ENDPOINT_G(rp->p_endpoint), rp->p_endpoint); printf(" %-8.8s %02u/%02u %02d/%02u %6lu%6lu %6uK %s", rp->p_name, rp->p_priority, rp->p_max_priority, rp->p_ticks_left, rp->p_quantum_size, rp->p_user_time, rp->p_sys_time, click_to_round_k(size), p_rts_flags_str(rp->p_rts_flags)); if (rp->p_rts_flags & (SENDING|RECEIVING)) { printf(" %-7.7s", proc_name(_ENDPOINT_P(rp->p_getfrom_e))); } printf("\n"); } if (rp == END_PROC_ADDR) rp = BEG_PROC_ADDR; else printf("--more--\r"); oldrp = rp; }
/*===========================================================================* * privileges_dmp * *===========================================================================*/ void privileges_dmp() { register struct proc *rp; static struct proc *oldrp = BEG_PROC_ADDR; register struct priv *sp; int r, i; /* First obtain a fresh copy of the current process and system table. */ if ((r = sys_getprivtab(priv)) != OK) { printf("IS: warning: couldn't get copy of system privileges table: %d\n", r); return; } if ((r = sys_getproctab(proc)) != OK) { printf("IS: warning: couldn't get copy of process table: %d\n", r); return; } printf("-nr- -id- -name-- -flags- traps grants -ipc_to--" " -kernel calls-\n"); PROCLOOP(rp, oldrp) r = -1; for (sp = &priv[0]; sp < &priv[NR_SYS_PROCS]; sp++) if (sp->s_proc_nr == rp->p_nr) { r ++; break; } if (r == -1 && !isemptyp(rp)) { sp = &priv[USER_PRIV_ID]; } printf("(%02u) %-7.7s %s %s %6d", sp->s_id, rp->p_name, s_flags_str(sp->s_flags), s_traps_str(sp->s_trap_mask), sp->s_grant_entries); for (i=0; i < NR_SYS_PROCS; i += BITCHUNK_BITS) { printf(" %08x", get_sys_bits(sp->s_ipc_to, i)); } printf(" "); for (i=0; i < NR_SYS_CALLS; i += BITCHUNK_BITS) { printf(" %08x", sp->s_k_call_mask[i/BITCHUNK_BITS]); } printf("\n"); }
int print_proc_summary(struct proc *proc) { int p, alive, running, sleeping; alive = running = sleeping = 0; for(p = 0; p < PROCS; p++) { if(p - NR_TASKS == IDLE) continue; if(isemptyp(&proc[p])) continue; alive++; if(!proc_is_runnable(&proc[p])) sleeping++; else running++; } printf("%d processes: %d running, %d sleeping\n", alive, running, sleeping); return 1; }
void vm_dmp() { static struct proc proc[NR_TASKS + NR_PROCS]; static struct vm_region_info vri[LINES]; struct vm_stats_info vsi; struct vm_usage_info vui; static int prev_i = -1; static vir_bytes prev_base = 0; int r, r2, i, j, first, n = 0; if (prev_i == -1) { if ((r = vm_info_stats(&vsi)) != OK) { printf("IS: warning: couldn't talk to VM: %d\n", r); return; } printf("Total %lu kB, free %lu kB, largest free %lu kB, cached %lu kB\n", vsi.vsi_total * (vsi.vsi_pagesize / 1024), vsi.vsi_free * (vsi.vsi_pagesize / 1024), vsi.vsi_largest * (vsi.vsi_pagesize / 1024), vsi.vsi_cached * (vsi.vsi_pagesize / 1024)); n++; printf("\n"); n++; prev_i++; } if ((r = sys_getproctab(proc)) != OK) { printf("IS: warning: couldn't get copy of process table: %d\n", r); return; } for (i = prev_i; i < NR_TASKS + NR_PROCS && n < LINES; i++, prev_base = 0) { if (i < NR_TASKS || isemptyp(&proc[i])) continue; /* The first batch dump for each process contains a header line. */ first = prev_base == 0; r = vm_info_region(proc[i].p_endpoint, vri, LINES - first, &prev_base); if (r < 0) { printf("Process %d (%s): error %d\n", proc[i].p_endpoint, proc[i].p_name, r); n++; continue; } if (first) { /* The entire batch should fit on the screen. */ if (n + 1 + r > LINES) { prev_base = 0; /* restart on next page */ break; } if ((r2 = vm_info_usage(proc[i].p_endpoint, &vui)) != OK) { printf("Process %d (%s): error %d\n", proc[i].p_endpoint, proc[i].p_name, r2); n++; continue; } printf("Process %d (%s): total %lu kB, common %lu kB, " "shared %lu kB\n", proc[i].p_endpoint, proc[i].p_name, vui.vui_total / 1024L, vui.vui_common / 1024L, vui.vui_shared / 1024L); n++; } while (r > 0) { for (j = 0; j < r; j++) { print_region(&vri[j], &n); } if (LINES - n - 1 <= 0) break; r = vm_info_region(proc[i].p_endpoint, vri, LINES - n - 1, &prev_base); if (r < 0) { printf("Process %d (%s): error %d\n", proc[i].p_endpoint, proc[i].p_name, r); n++; } } print_region(NULL, &n); if (n > LINES) printf("IS: internal error\n"); if (n == LINES) break; /* This may have to wipe out the "--more--" from below. */ printf(" \n"); n++; } if (i >= NR_TASKS + NR_PROCS) { i = -1; prev_base = 0; } else printf("--more--\r"); prev_i = i; }
/*===========================================================================* * 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; struct rusage r_usage; /* 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) kinfo.param_buf; length = sizeof(kinfo.param_buf); 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_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; } case GET_RUSAGE: { struct proc *target = NULL; int target_slot = 0; u64_t usec; nr_e = (m_ptr->I_VAL_LEN2_E == SELF) ? caller->p_endpoint : m_ptr->I_VAL_LEN2_E; if (!isokendpt(nr_e, &target_slot)) return EINVAL; target = proc_addr(target_slot); if (isemptyp(target)) return EINVAL; length = sizeof(r_usage); memset(&r_usage, 0, sizeof(r_usage)); usec = target->p_user_time * 1000000 / system_hz; r_usage.ru_utime.tv_sec = usec / 1000000; r_usage.ru_utime.tv_usec = usec % 100000; usec = target->p_sys_time * 1000000 / system_hz; r_usage.ru_stime.tv_sec = usec / 1000000; r_usage.ru_stime.tv_usec = usec % 100000; r_usage.ru_nsignals = target->p_signal_received; src_vir = (vir_bytes) &r_usage; 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); }
void print_procs(int maxlines, struct proc *proc1, struct proc *proc2, struct mproc *mproc) { int p, nprocs, tot=0; u64_t idleticks = cvu64(0); u64_t kernelticks = cvu64(0); u64_t systemticks = cvu64(0); u64_t userticks = cvu64(0); u64_t total_ticks = cvu64(0); unsigned long tcyc; unsigned long tmp; int blockedseen = 0; struct tp tick_procs[PROCS]; for(p = nprocs = 0; p < PROCS; p++) { if(isemptyp(&proc2[p])) continue; tick_procs[nprocs].p = proc2 + p; if(proc1[p].p_endpoint == proc2[p].p_endpoint) { tick_procs[nprocs].ticks = sub64(proc2[p].p_cycles, proc1[p].p_cycles); } else { tick_procs[nprocs].ticks = proc2[p].p_cycles; } total_ticks = add64(total_ticks, tick_procs[nprocs].ticks); if(p-NR_TASKS == IDLE) { idleticks = tick_procs[nprocs].ticks; continue; } if(p-NR_TASKS == KERNEL) { kernelticks = tick_procs[nprocs].ticks; continue; } if(mproc[proc2[p].p_nr].mp_procgrp == 0) systemticks = add64(systemticks, tick_procs[nprocs].ticks); else if (p > NR_TASKS) userticks = add64(userticks, tick_procs[nprocs].ticks); nprocs++; } if (!cmp64u(total_ticks, 0)) return; qsort(tick_procs, nprocs, sizeof(tick_procs[0]), cmp_ticks); tcyc = div64u(total_ticks, SCALE); tmp = div64u(userticks, SCALE); printf("CPU states: %6.2f%% user, ", 100.0*(tmp)/tcyc); tmp = div64u(systemticks, SCALE); printf("%6.2f%% system, ", 100.0*tmp/tcyc); tmp = div64u(kernelticks, SCALE); printf("%6.2f%% kernel, ", 100.0*tmp/tcyc); tmp = div64u(idleticks, SCALE); printf("%6.2f%% idle", 100.0*tmp/tcyc); #define NEWLINE do { printf("\n"); if(--maxlines <= 0) { return; } } while(0) NEWLINE; NEWLINE; printf(" PID USERNAME PRI NICE SIZE STATE TIME CPU COMMAND"); NEWLINE; for(p = 0; p < nprocs; p++) { struct proc *pr; int pnr; int level = 0; pnr = tick_procs[p].p->p_nr; if(pnr < 0) { /* skip old kernel tasks as they don't run anymore */ continue; } pr = tick_procs[p].p; /* If we're in blocked verbose mode, indicate start of * blocked processes. */ if(blockedverbose && pr->p_rts_flags && !blockedseen) { NEWLINE; printf("Blocked processes:"); NEWLINE; blockedseen = 1; } print_proc(&tick_procs[p], &mproc[pnr], tcyc); NEWLINE; if(!blockedverbose) continue; /* Traverse dependency chain if blocked. */ while(pr->p_rts_flags) { endpoint_t dep = NONE; struct tp *tpdep; level += 5; if((dep = P_BLOCKEDON(pr)) == NONE) { printf("not blocked on a process"); NEWLINE; break; } if(dep == ANY) break; tpdep = lookup(dep, tick_procs, nprocs); pr = tpdep->p; printf("%*s> ", level, ""); print_proc(tpdep, &mproc[pr->p_nr], tcyc); NEWLINE; } } }
/*===========================================================================* * do_clear * *===========================================================================*/ int do_clear(struct proc * caller, message * m_ptr) { /* Handle sys_clear. Only the PM can request other process slots to be cleared * when a process has exited. * The routine to clean up a process table slot cancels outstanding timers, * possibly removes the process from the message queues, and resets certain * process table fields to the default values. */ struct proc *rc; int exit_p; int i; if(!isokendpt(m_ptr->PR_ENDPT, &exit_p)) { /* get exiting process */ return EINVAL; } rc = proc_addr(exit_p); /* clean up */ release_address_space(rc); /* Don't clear if already cleared. */ if(isemptyp(rc)) return OK; /* Check the table with IRQ hooks to see if hooks should be released. */ for (i=0; i < NR_IRQ_HOOKS; i++) { if (rc->p_endpoint == irq_hooks[i].proc_nr_e) { rm_irq_handler(&irq_hooks[i]); /* remove interrupt handler */ irq_hooks[i].proc_nr_e = NONE; /* mark hook as free */ } } /* Remove the process' ability to send and receive messages */ clear_endpoint(rc); /* Turn off any alarm timers at the clock. */ reset_timer(&priv(rc)->s_alarm_timer); /* Make sure that the exiting process is no longer scheduled, * and mark slot as FREE. Also mark saved fpu contents as not significant. */ RTS_SETFLAGS(rc, RTS_SLOT_FREE); /* release FPU */ release_fpu(rc); rc->p_misc_flags &= ~MF_FPU_INITIALIZED; /* Release the process table slot. If this is a system process, also * release its privilege structure. Further cleanup is not needed at * this point. All important fields are reinitialized when the * slots are assigned to another, new process. */ if (priv(rc)->s_flags & SYS_PROC) priv(rc)->s_proc_nr = NONE; #if 0 /* Clean up virtual memory */ if (rc->p_misc_flags & MF_VM) { vm_map_default(rc); } #endif return OK; }
/*==========================================================================* * do_trace * *==========================================================================*/ PUBLIC int do_trace(struct proc * caller, message * m_ptr) { /* Handle the debugging commands supported by the ptrace system call * The commands are: * T_STOP stop the process * T_OK enable tracing by parent for this process * T_GETINS return value from instruction space * T_GETDATA return value from data space * T_GETUSER return value from user process table * T_SETINS set value in instruction space * T_SETDATA set value in data space * T_SETUSER set value in user process table * T_RESUME resume execution * T_EXIT exit * T_STEP set trace bit * T_SYSCALL trace system call * T_ATTACH attach to an existing process * T_DETACH detach from a traced process * T_SETOPT set trace options * T_GETRANGE get range of values * T_SETRANGE set range of values * * The T_OK, T_ATTACH, T_EXIT, and T_SETOPT commands are handled completely by * the process manager. T_GETRANGE and T_SETRANGE use sys_vircopy(). All others * come here. */ register struct proc *rp; vir_bytes tr_addr = (vir_bytes) m_ptr->CTL_ADDRESS; long tr_data = m_ptr->CTL_DATA; int tr_request = m_ptr->CTL_REQUEST; int tr_proc_nr_e = m_ptr->CTL_ENDPT, tr_proc_nr; unsigned char ub; int i; #define COPYTOPROC(seg, addr, myaddr, length) { \ struct vir_addr fromaddr, toaddr; \ int r; \ fromaddr.proc_nr_e = KERNEL; \ toaddr.proc_nr_e = tr_proc_nr_e; \ fromaddr.offset = (myaddr); \ toaddr.offset = (addr); \ fromaddr.segment = D; \ toaddr.segment = (seg); \ if((r=virtual_copy_vmcheck(caller, &fromaddr, \ &toaddr, length)) != OK) { \ printf("Can't copy in sys_trace: %d\n", r);\ return r;\ } \ } #define COPYFROMPROC(seg, addr, myaddr, length) { \ struct vir_addr fromaddr, toaddr; \ int r; \ fromaddr.proc_nr_e = tr_proc_nr_e; \ toaddr.proc_nr_e = KERNEL; \ fromaddr.offset = (addr); \ toaddr.offset = (myaddr); \ fromaddr.segment = (seg); \ toaddr.segment = D; \ if((r=virtual_copy_vmcheck(caller, &fromaddr, \ &toaddr, length)) != OK) { \ printf("Can't copy in sys_trace: %d\n", r);\ return r;\ } \ } if(!isokendpt(tr_proc_nr_e, &tr_proc_nr)) return(EINVAL); if (iskerneln(tr_proc_nr)) return(EPERM); rp = proc_addr(tr_proc_nr); if (isemptyp(rp)) return(EINVAL); switch (tr_request) { case T_STOP: /* stop process */ RTS_SET(rp, RTS_P_STOP); rp->p_reg.psw &= ~TRACEBIT; /* clear trace bit */ rp->p_misc_flags &= ~MF_SC_TRACE; /* clear syscall trace flag */ return(OK); case T_GETINS: /* return value from instruction space */ COPYFROMPROC(T, tr_addr, (vir_bytes) &tr_data, sizeof(long)); m_ptr->CTL_DATA = tr_data; break; case T_GETDATA: /* return value from data space */ COPYFROMPROC(D, tr_addr, (vir_bytes) &tr_data, sizeof(long)); m_ptr->CTL_DATA= tr_data; break; case T_GETUSER: /* return value from process table */ if ((tr_addr & (sizeof(long) - 1)) != 0) return(EFAULT); if (tr_addr <= sizeof(struct proc) - sizeof(long)) { m_ptr->CTL_DATA = *(long *) ((char *) rp + (int) tr_addr); break; } /* The process's proc struct is followed by its priv struct. * The alignment here should be unnecessary, but better safe.. */ i = sizeof(long) - 1; tr_addr -= (sizeof(struct proc) + i) & ~i; if (tr_addr > sizeof(struct priv) - sizeof(long)) return(EFAULT); m_ptr->CTL_DATA = *(long *) ((char *) rp->p_priv + (int) tr_addr); break; case T_SETINS: /* set value in instruction space */ COPYTOPROC(T, tr_addr, (vir_bytes) &tr_data, sizeof(long)); m_ptr->CTL_DATA = 0; break; case T_SETDATA: /* set value in data space */ COPYTOPROC(D, tr_addr, (vir_bytes) &tr_data, sizeof(long)); m_ptr->CTL_DATA = 0; break; case T_SETUSER: /* set value in process table */ if ((tr_addr & (sizeof(reg_t) - 1)) != 0 || tr_addr > sizeof(struct stackframe_s) - sizeof(reg_t)) return(EFAULT); i = (int) tr_addr; #if (_MINIX_CHIP == _CHIP_INTEL) /* Altering segment registers might crash the kernel when it * tries to load them prior to restarting a process, so do * not allow it. */ if (i == (int) &((struct proc *) 0)->p_reg.cs || i == (int) &((struct proc *) 0)->p_reg.ds || i == (int) &((struct proc *) 0)->p_reg.es || #if _WORD_SIZE == 4 i == (int) &((struct proc *) 0)->p_reg.gs || i == (int) &((struct proc *) 0)->p_reg.fs || #endif i == (int) &((struct proc *) 0)->p_reg.ss) return(EFAULT); #endif if (i == (int) &((struct proc *) 0)->p_reg.psw) /* only selected bits are changeable */ SETPSW(rp, tr_data); else *(reg_t *) ((char *) &rp->p_reg + i) = (reg_t) tr_data; m_ptr->CTL_DATA = 0; break; case T_DETACH: /* detach tracer */ rp->p_misc_flags &= ~MF_SC_ACTIVE; /* fall through */ case T_RESUME: /* resume execution */ RTS_UNSET(rp, RTS_P_STOP); m_ptr->CTL_DATA = 0; break; case T_STEP: /* set trace bit */ rp->p_reg.psw |= TRACEBIT; RTS_UNSET(rp, RTS_P_STOP); m_ptr->CTL_DATA = 0; break; case T_SYSCALL: /* trace system call */ rp->p_misc_flags |= MF_SC_TRACE; RTS_UNSET(rp, RTS_P_STOP); m_ptr->CTL_DATA = 0; break; case T_READB_INS: /* get value from instruction space */ COPYFROMPROC(T, tr_addr, (vir_bytes) &ub, 1); m_ptr->CTL_DATA = ub; break; case T_WRITEB_INS: /* set value in instruction space */ ub = (unsigned char) (tr_data & 0xff); COPYTOPROC(T, tr_addr, (vir_bytes) &ub, 1); m_ptr->CTL_DATA = 0; break; default: return(EINVAL); } return(OK); }
int runqueues_ok_cpu(unsigned cpu) { int q, l = 0; register struct proc *xp; struct proc **rdy_head, **rdy_tail; rdy_head = get_cpu_var(cpu, run_q_head); rdy_tail = get_cpu_var(cpu, run_q_tail); for (xp = BEG_PROC_ADDR; xp < END_PROC_ADDR; ++xp) { xp->p_found = 0; if (l++ > MAX_LOOP) panic("check error"); } for (q=l=0; q < NR_SCHED_QUEUES; q++) { if (rdy_head[q] && !rdy_tail[q]) { printf("head but no tail in %d\n", q); return 0; } if (!rdy_head[q] && rdy_tail[q]) { printf("tail but no head in %d\n", q); return 0; } if (rdy_tail[q] && rdy_tail[q]->p_nextready) { printf("tail and tail->next not null in %d\n", q); return 0; } for(xp = rdy_head[q]; xp; xp = xp->p_nextready) { const vir_bytes vxp = (vir_bytes) xp; vir_bytes dxp; if(vxp < (vir_bytes) BEG_PROC_ADDR || vxp >= (vir_bytes) END_PROC_ADDR) { printf("xp out of range\n"); return 0; } dxp = vxp - (vir_bytes) BEG_PROC_ADDR; if(dxp % sizeof(struct proc)) { printf("xp not a real pointer"); return 0; } if(!proc_ptr_ok(xp)) { printf("xp bogus pointer"); return 0; } if (RTS_ISSET(xp, RTS_SLOT_FREE)) { printf("scheduling error: dead proc q %d %d\n", q, xp->p_endpoint); return 0; } if (!proc_is_runnable(xp)) { printf("scheduling error: unready on runq %d proc %d\n", q, xp->p_nr); return 0; } if (xp->p_priority != q) { printf("scheduling error: wrong priority q %d proc %d ep %d name %s\n", q, xp->p_nr, xp->p_endpoint, xp->p_name); return 0; } if (xp->p_found) { printf("scheduling error: double sched q %d proc %d\n", q, xp->p_nr); return 0; } xp->p_found = 1; if (!xp->p_nextready && rdy_tail[q] != xp) { printf("sched err: last element not tail q %d proc %d\n", q, xp->p_nr); return 0; } if (l++ > MAX_LOOP) { printf("loop in schedule queue?"); return 0; } } } for (xp = BEG_PROC_ADDR; xp < END_PROC_ADDR; ++xp) { if(!proc_ptr_ok(xp)) { printf("xp bogus pointer in proc table\n"); return 0; } if (isemptyp(xp)) continue; if(proc_is_runnable(xp) && !xp->p_found) { printf("sched error: ready proc %d not on queue\n", xp->p_nr); return 0; } } /* All is ok. */ return 1; }
/*===========================================================================* * do_fork * *===========================================================================*/ int do_fork(struct proc * caller, message * m_ptr) { /* Handle sys_fork(). * m_lsys_krn_sys_fork.endpt has forked. * The child is m_lsys_krn_sys_fork.slot. */ #if defined(__i386__) char *old_fpu_save_area_p; #endif register struct proc *rpc; /* child process pointer */ struct proc *rpp; /* parent process pointer */ int gen; int p_proc; int namelen; if(!isokendpt(m_ptr->m_lsys_krn_sys_fork.endpt, &p_proc)) return EINVAL; rpp = proc_addr(p_proc); rpc = proc_addr(m_ptr->m_lsys_krn_sys_fork.slot); if (isemptyp(rpp) || ! isemptyp(rpc)) return(EINVAL); assert(!(rpp->p_misc_flags & MF_DELIVERMSG)); /* needs to be receiving so we know where the message buffer is */ if(!RTS_ISSET(rpp, RTS_RECEIVING)) { printf("kernel: fork not done synchronously?\n"); return EINVAL; } /* make sure that the FPU context is saved in parent before copy */ save_fpu(rpp); /* Copy parent 'proc' struct to child. And reinitialize some fields. */ gen = _ENDPOINT_G(rpc->p_endpoint); #if defined(__i386__) old_fpu_save_area_p = rpc->p_seg.fpu_state; #endif *rpc = *rpp; /* copy 'proc' struct */ #if defined(__i386__) rpc->p_seg.fpu_state = old_fpu_save_area_p; if(proc_used_fpu(rpp)) memcpy(rpc->p_seg.fpu_state, rpp->p_seg.fpu_state, FPU_XFP_SIZE); #endif if(++gen >= _ENDPOINT_MAX_GENERATION) /* increase generation */ gen = 1; /* generation number wraparound */ rpc->p_nr = m_ptr->m_lsys_krn_sys_fork.slot; /* this was obliterated by copy */ rpc->p_endpoint = _ENDPOINT(gen, rpc->p_nr); /* new endpoint of slot */ rpc->p_reg.retreg = 0; /* child sees pid = 0 to know it is child */ rpc->p_user_time = 0; /* set all the accounting times to 0 */ rpc->p_sys_time = 0; rpc->p_misc_flags &= ~(MF_VIRT_TIMER | MF_PROF_TIMER | MF_SC_TRACE | MF_SPROF_SEEN | MF_STEP); rpc->p_virt_left = 0; /* disable, clear the process-virtual timers */ rpc->p_prof_left = 0; /* Mark process name as being a forked copy */ namelen = strlen(rpc->p_name); #define FORKSTR "*F" if(namelen+strlen(FORKSTR) < sizeof(rpc->p_name)) strcat(rpc->p_name, FORKSTR); /* the child process is not runnable until it's scheduled. */ RTS_SET(rpc, RTS_NO_QUANTUM); reset_proc_accounting(rpc); rpc->p_cpu_time_left = 0; rpc->p_cycles = 0; rpc->p_kcall_cycles = 0; rpc->p_kipc_cycles = 0; rpc->p_signal_received = 0; /* If the parent is a privileged process, take away the privileges from the * child process and inhibit it from running by setting the NO_PRIV flag. * The caller should explicitly set the new privileges before executing. */ if (priv(rpp)->s_flags & SYS_PROC) { rpc->p_priv = priv_addr(USER_PRIV_ID); rpc->p_rts_flags |= RTS_NO_PRIV; } /* Calculate endpoint identifier, so caller knows what it is. */ m_ptr->m_krn_lsys_sys_fork.endpt = rpc->p_endpoint; m_ptr->m_krn_lsys_sys_fork.msgaddr = rpp->p_delivermsg_vir; /* Don't schedule process in VM mode until it has a new pagetable. */ if(m_ptr->m_lsys_krn_sys_fork.flags & PFF_VMINHIBIT) { RTS_SET(rpc, RTS_VMINHIBIT); } /* * Only one in group should have RTS_SIGNALED, child doesn't inherit tracing. */ RTS_UNSET(rpc, (RTS_SIGNALED | RTS_SIG_PENDING | RTS_P_STOP)); (void) sigemptyset(&rpc->p_pending); #if defined(__i386__) rpc->p_seg.p_cr3 = 0; rpc->p_seg.p_cr3_v = NULL; #elif defined(__arm__) rpc->p_seg.p_ttbr = 0; rpc->p_seg.p_ttbr_v = NULL; #endif return OK; }
PUBLIC void vm_init(void) { int o; phys_bytes p, pt_size; phys_bytes vm_dir_base, vm_pt_base, phys_mem; u32_t entry; unsigned pages; struct proc* rp; struct proc *sys = proc_addr(SYSTEM); static int init_done = 0; if (!vm_size) minix_panic("i386_vm_init: no space for page tables", NO_NUM); if(init_done) return; /* Align page directory */ o= (vm_base % I386_PAGE_SIZE); if (o != 0) o= I386_PAGE_SIZE-o; vm_dir_base= vm_base+o; /* Page tables start after the page directory */ vm_pt_base= vm_dir_base+I386_PAGE_SIZE; pt_size= (vm_base+vm_size)-vm_pt_base; pt_size -= (pt_size % I386_PAGE_SIZE); /* Compute the number of pages based on vm_mem_high */ pages= (vm_mem_high-1)/I386_PAGE_SIZE + 1; if (pages * I386_VM_PT_ENT_SIZE > pt_size) minix_panic("i386_vm_init: page table too small", NO_NUM); for (p= 0; p*I386_VM_PT_ENT_SIZE < pt_size; p++) { phys_mem= p*I386_PAGE_SIZE; entry= phys_mem | I386_VM_USER | I386_VM_WRITE | I386_VM_PRESENT; if (phys_mem >= vm_mem_high) entry= 0; #if VM_KERN_NOPAGEZERO if (phys_mem == (sys->p_memmap[T].mem_phys << CLICK_SHIFT) || phys_mem == (sys->p_memmap[D].mem_phys << CLICK_SHIFT)) { entry = 0; } #endif phys_put32(vm_pt_base + p*I386_VM_PT_ENT_SIZE, entry); } for (p= 0; p < I386_VM_DIR_ENTRIES; p++) { phys_mem= vm_pt_base + p*I386_PAGE_SIZE; entry= phys_mem | I386_VM_USER | I386_VM_WRITE | I386_VM_PRESENT; if (phys_mem >= vm_pt_base + pt_size) entry= 0; phys_put32(vm_dir_base + p*I386_VM_PT_ENT_SIZE, entry); } /* Set this cr3 in all currently running processes for * future context switches. */ for (rp=BEG_PROC_ADDR; rp<END_PROC_ADDR; rp++) { u32_t mycr3; if(isemptyp(rp)) continue; rp->p_seg.p_cr3 = vm_dir_base; } kernel_cr3 = vm_dir_base; /* Set this cr3 now (not active until paging enabled). */ vm_set_cr3(vm_dir_base); /* Actually enable paging (activating cr3 load above). */ level0(vm_enable_paging); /* Don't do this init in the future. */ init_done = 1; vm_running = 1; }