/*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include <sys/disklabel.h>
#include <sys/vm.h>
#include <sys/sysctl.h>
+#include <sys/user.h>
#include <mach/machine.h>
#include <mach/mach_types.h>
#include <mach/vm_param.h>
#include <pexpert/pexpert.h>
#if __ppc__
-#include <osfmk/ppc/machine_routines.h>
+#include <ppc/machine_routines.h>
#endif
sysctlfn kern_sysctl;
/*
* temporary location for vm_sysctl. This should be machine independant
*/
+int
vm_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
int *name;
u_int namelen;
size_t newlen;
struct proc *p;
{
- int error, level, inthostid;
- extern long avenrun[3], mach_factor[3];
+ extern uint32_t mach_factor[3];
struct loadavg loadinfo;
- //if (namelen != 1 && !(name[0] == VM_LOADAVG))
- //return (ENOTDIR); /* overloaded */
-
switch (name[0]) {
case VM_LOADAVG:
- loadinfo.ldavg[0] = avenrun[0];
- loadinfo.ldavg[1] = avenrun[1];
- loadinfo.ldavg[2] = avenrun[2];
- loadinfo.fscale = LSCALE;
- return (sysctl_struct(oldp, oldlenp, newp, newlen, &loadinfo, sizeof(struct loadavg)));
+ return (sysctl_struct(oldp, oldlenp, newp, newlen,
+ &averunnable, sizeof(struct loadavg)));
case VM_MACHFACTOR:
loadinfo.ldavg[0] = mach_factor[0];
loadinfo.ldavg[1] = mach_factor[1];
loadinfo.ldavg[2] = mach_factor[2];
loadinfo.fscale = LSCALE;
- return (sysctl_struct(oldp, oldlenp, newp, newlen, &loadinfo, sizeof(struct loadavg)));
+ return (sysctl_struct(oldp, oldlenp, newp, newlen,
+ &loadinfo, sizeof(struct loadavg)));
case VM_METER:
return (EOPNOTSUPP);
case VM_MAXID:
sysctlfn *fn;
int name[CTL_MAXNAME];
int i;
+ int error1;
/*
* all top-level sysctl names are non-terminal
return (error);
/* CTL_UNSPEC is used to get oid to AUTO_OID */
- if (uap->new != NULL &&
- (((name[0] == CTL_KERN) && (name[1] != KERN_IPC)) ||
- (name[0] == CTL_HW) || (name[0] == CTL_VM) ||
- (name[0] == CTL_VFS)) &&
- (error = suser(p->p_ucred, &p->p_acflag)))
+ if (uap->new != NULL
+ && ((name[0] == CTL_KERN
+ && !(name[1] == KERN_IPC || name[1] == KERN_PANICINFO))
+ || (name[0] == CTL_HW)
+ || (name[0] == CTL_VM)
+ || (name[0] == CTL_VFS))
+ && (error = suser(p->p_ucred, &p->p_acflag)))
return (error);
switch (name[0]) {
case CTL_KERN:
fn = kern_sysctl;
- if (name[1] != KERN_VNODE) /* XXX */
+ if ((name[1] != KERN_VNODE) && (name[1] != KERN_FILE)
+ && (name[1] != KERN_PROC))
dolock = 0;
break;
case CTL_HW:
case CTL_VFS:
fn = vfs_sysctl;
break;
-#if FIXME /* [ */
- case CTL_MACHDEP:
- fn = cpu_sysctl;
- break;
-#endif /* FIXME ] */
#ifdef DEBUG
case CTL_DEBUG:
fn = debug_sysctl;
return (EFAULT);
/* The pc sampling mechanism does not need to take this lock */
- if (name[1] != KERN_PCSAMPLES) {
+ if ((name[1] != KERN_PCSAMPLES) &&
+ (!((name[1] == KERN_KDEBUG) && (name[2] == KERN_KDGETENTROPY)))) {
while (memlock.sl_lock) {
memlock.sl_want = 1;
sleep((caddr_t)&memlock, PRIBIO+1);
memlock.sl_lock = 1;
}
- if (dolock)
- vslock(uap->old, oldlen);
+ if (dolock && oldlen && (error = vslock(uap->old, oldlen))) {
+ if ((name[1] != KERN_PCSAMPLES) &&
+ (! ((name[1] == KERN_KDEBUG) && (name[2] == KERN_KDGETENTROPY)))) {
+ memlock.sl_lock = 0;
+ if (memlock.sl_want) {
+ memlock.sl_want = 0;
+ wakeup((caddr_t)&memlock);
+ }
+ }
+ return(error);
+ }
savelen = oldlen;
}
uap->new, uap->newlen, &oldlen);
if (uap->old != NULL) {
- if (dolock)
- vsunlock(uap->old, savelen, B_WRITE);
+ if (dolock && savelen) {
+ error1 = vsunlock(uap->old, savelen, B_WRITE);
+ if (!error && error1)
+ error = error1;
+ }
if (name[1] != KERN_PCSAMPLES) {
memlock.sl_lock = 0;
if (memlock.sl_want) {
int securelevel;
#endif
-int get_kernel_symfile( struct proc *p, char **symfile );
+extern int get_kernel_symfile( struct proc *, char **);
+extern int sysctl_dopanicinfo(int *, u_int, void *, size_t *,
+ void *, size_t, struct proc *);
/*
* kernel related system variables.
*/
+int
kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
int *name;
u_int namelen;
{
int error, level, inthostid;
unsigned int oldval=0;
+ char *str;
extern char ostype[], osrelease[], version[];
-
- /* all sysctl names at this level are terminal */
- if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF
- || name[0] == KERN_KDEBUG
- || name[0] == KERN_PROCARGS
- || name[0] == KERN_PCSAMPLES
- || name[0] == KERN_IPC
- ))
+ extern int netboot_root();
+
+ /* all sysctl names not listed below are terminal at this level */
+ if (namelen != 1
+ && !(name[0] == KERN_PROC
+ || name[0] == KERN_PROF
+ || name[0] == KERN_KDEBUG
+ || name[0] == KERN_PROCARGS
+ || name[0] == KERN_PCSAMPLES
+ || name[0] == KERN_IPC
+ || name[0] == KERN_SYSV
+ || name[0] == KERN_PANICINFO)
+ )
return (ENOTDIR); /* overloaded */
switch (name[0]) {
#else
return (sysctl_rdint(oldp, oldlenp, newp, 0));
#endif
-#if FIXME /* [ */
- case KERN_MAXPARTITIONS:
- return (sysctl_rdint(oldp, oldlenp, newp, MAXPARTITIONS));
-#endif /* FIXME ] */
case KERN_KDEBUG:
return (kdebug_ops(name + 1, namelen - 1, oldp, oldlenp, p));
case KERN_PCSAMPLES:
return (pcsamples_ops(name + 1, namelen - 1, oldp, oldlenp, p));
case KERN_PROCARGS:
/* new one as it does not use kinfo_proc */
- return (sysctl_procargs(name + 1, namelen - 1, oldp, oldlenp));
- case KERN_SYMFILE:
- {
- char *str;
- error = get_kernel_symfile( p, &str );
- if ( error ) return error;
- return (sysctl_rdstring(oldp, oldlenp, newp, str));
- }
+ return (sysctl_procargs(name + 1, namelen - 1, oldp, oldlenp, p));
+ case KERN_SYMFILE:
+ error = get_kernel_symfile( p, &str );
+ if ( error )
+ return error;
+ return (sysctl_rdstring(oldp, oldlenp, newp, str));
+ case KERN_NETBOOT:
+ return (sysctl_rdint(oldp, oldlenp, newp, netboot_root()));
+ case KERN_PANICINFO:
+ return(sysctl_dopanicinfo(name + 1, namelen - 1, oldp, oldlenp,
+ newp, newlen, p));
default:
return (EOPNOTSUPP);
}
if(!PEGetModelName(dummy,64))
return(EINVAL);
return (sysctl_rdstring(oldp, oldlenp, newp, dummy));
- case HW_NCPU: {
+ case HW_NCPU:
+ {
int numcpus=1;
host_basic_info_data_t hinfo;
kern_return_t kret;
return (sysctl_rdint(oldp, oldlenp, newp, gPEClockFrequencyInfo.bus_clock_rate_hz));
case HW_CPU_FREQ:
return (sysctl_rdint(oldp, oldlenp, newp, gPEClockFrequencyInfo.cpu_clock_rate_hz));
+ case HW_TB_FREQ:
+ return (sysctl_rdint(oldp, oldlenp, newp, gPEClockFrequencyInfo.timebase_frequency_hz));
#if __ppc__
case HW_VECTORUNIT:
return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.vector_unit));
* Validate parameters and get old / set new parameters
* for an integer-valued sysctl function.
*/
+int
sysctl_int(oldp, oldlenp, newp, newlen, valp)
void *oldp;
size_t *oldlenp;
/*
* As above, but read-only.
*/
+int
sysctl_rdint(oldp, oldlenp, newp, val)
void *oldp;
size_t *oldlenp;
return (error);
}
+/*
+ * Validate parameters and get old / set new parameters
+ * for an quad(64bit)-valued sysctl function.
+ */
+int
+sysctl_quad(oldp, oldlenp, newp, newlen, valp)
+ void *oldp;
+ size_t *oldlenp;
+ void *newp;
+ size_t newlen;
+ quad_t *valp;
+{
+ int error = 0;
+
+ if (oldp && *oldlenp < sizeof(quad_t))
+ return (ENOMEM);
+ if (newp && newlen != sizeof(quad_t))
+ return (EINVAL);
+ *oldlenp = sizeof(quad_t);
+ if (oldp)
+ error = copyout(valp, oldp, sizeof(quad_t));
+ if (error == 0 && newp)
+ error = copyin(newp, valp, sizeof(quad_t));
+ return (error);
+}
+
+/*
+ * As above, but read-only.
+ */
+int
+sysctl_rdquad(oldp, oldlenp, newp, val)
+ void *oldp;
+ size_t *oldlenp;
+ void *newp;
+ quad_t val;
+{
+ int error = 0;
+
+ if (oldp && *oldlenp < sizeof(quad_t))
+ return (ENOMEM);
+ if (newp)
+ return (EPERM);
+ *oldlenp = sizeof(quad_t);
+ if (oldp)
+ error = copyout((caddr_t)&val, oldp, sizeof(quad_t));
+ return (error);
+}
+
/*
* Validate parameters and get old / set new parameters
* for a string-valued sysctl function.
*/
+int
sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen)
void *oldp;
size_t *oldlenp;
return (ENOMEM);
if (newp && newlen >= maxlen)
return (EINVAL);
+ *oldlenp = len -1; /* deal with NULL strings correctly */
if (oldp) {
- *oldlenp = len;
error = copyout(str, oldp, len);
}
if (error == 0 && newp) {
/*
* As above, but read-only.
*/
+int
sysctl_rdstring(oldp, oldlenp, newp, str)
void *oldp;
size_t *oldlenp;
* Validate parameters and get old / set new parameters
* for a structure oriented sysctl function.
*/
+int
sysctl_struct(oldp, oldlenp, newp, newlen, sp, len)
void *oldp;
size_t *oldlenp;
* Validate parameters and get old parameters
* for a structure oriented sysctl function.
*/
+int
sysctl_rdstruct(oldp, oldlenp, newp, sp, len)
void *oldp;
size_t *oldlenp;
/*
* Get file structures.
*/
+int
sysctl_file(where, sizep)
char *where;
size_t *sizep;
*/
#define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc))
+int
sysctl_doproc(name, namelen, where, sizep)
int *name;
u_int namelen;
break;
}
if (buflen >= sizeof(struct kinfo_proc)) {
+ bzero(&kproc, sizeof(struct kinfo_proc));
fill_proc(p, &kproc, doingzomb);
if (error = copyout((caddr_t)&kproc, &dp->kp_proc,
sizeof(struct kinfo_proc)))
{
register struct tty *tp;
+ /*
+ * Skip zombie processes.
+ */
+ if (p->p_stat == SZOMB)
+ return;
+
ep->e_paddr = p;
ep->e_sess = p->p_pgrp->pg_session;
ep->e_pcred = *p->p_cred;
ep->e_ucred = *p->p_ucred;
if (p->p_stat == SIDL || p->p_stat == SZOMB) {
- ep->e_vm.vm_rssize = 0;
ep->e_vm.vm_tsize = 0;
ep->e_vm.vm_dsize = 0;
ep->e_vm.vm_ssize = 0;
- /* ep->e_vm.vm_pmap = XXX; */
- } else {
-#if FIXME /* [ */
- register vm_map_t vm = ((task_t)p->task)->map;
-
- ep->e_vm.vm_rssize = pmap_resident_count(vm->pmap); /*XXX*/
-// ep->e_vm.vm_tsize = vm->vm_tsize;
-// ep->e_vm.vm_dsize = vm->vm_dsize;
-// ep->e_vm.vm_ssize = vm->vm_ssize;
-#else /* FIXME ][ */
- ep->e_vm.vm_rssize = 0; /*XXX*/
-#endif /* FIXME ] */
}
+ ep->e_vm.vm_rssize = 0;
if (p->p_pptr)
ep->e_ppid = p->p_pptr->p_pid;
else
register struct extern_proc *exp;
{
exp->p_forw = exp->p_back = NULL;
+ if (p->p_stats)
+ exp->p_starttime = p->p_stats->p_start;
exp->p_vmspace = NULL;
exp->p_sigacts = p->p_sigacts;
exp->p_flag = p->p_flag;
exp->p_iticks = p->p_iticks ;
exp->p_traceflag = p->p_traceflag ;
exp->p_tracep = p->p_tracep ;
- exp->p_siglist = p->p_siglist ;
+ exp->p_siglist = 0 ; /* No longer relevant */
exp->p_textvp = p->p_textvp ;
exp->p_holdcnt = 0 ;
- exp->p_sigmask = p->p_sigmask ;
+ exp->p_sigmask = 0 ; /* no longer avaialable */
exp->p_sigignore = p->p_sigignore ;
exp->p_sigcatch = p->p_sigcatch ;
exp->p_priority = p->p_priority ;
exp->p_ru = p->p_ru ;
}
+int
kdebug_ops(name, namelen, where, sizep, p)
int *name;
u_int namelen;
size_t *sizep;
struct proc *p;
{
-int size=*sizep;
-int ret=0;
-extern int kdbg_control(int *name, u_int namelen, char * where,size_t * sizep);
+ int size=*sizep;
+ int ret=0;
+ extern int kdbg_control(int *name, u_int namelen,
+ char * where,size_t * sizep);
- if (ret = suser(p->p_ucred, &p->p_acflag))
- return(ret);
+ if (ret = suser(p->p_ucred, &p->p_acflag))
+ return(ret);
switch(name[0]) {
case KERN_KDEFLAGS:
case KERN_KDPIDEX:
case KERN_KDSETRTCDEC:
case KERN_KDSETBUF:
+ case KERN_KDGETENTROPY:
ret = kdbg_control(name, namelen, where, sizep);
break;
default:
return(ret);
}
+int
pcsamples_ops(name, namelen, where, sizep, p)
int *name;
u_int namelen;
size_t *sizep;
struct proc *p;
{
-int ret=0;
-extern int pcsamples_control(int *name, u_int namelen, char * where,size_t * sizep);
+ int ret=0;
+ extern int pcsamples_control(int *name, u_int namelen,
+ char * where,size_t * sizep);
- if (ret = suser(p->p_ucred, &p->p_acflag))
- return(ret);
+ if (ret = suser(p->p_ucred, &p->p_acflag))
+ return(ret);
switch(name[0]) {
case KERN_PCDISABLE:
* zeroed for security reasons.
* Odd data structure is for compatibility.
*/
-sysctl_procargs(name, namelen, where, sizep)
+int
+sysctl_procargs(name, namelen, where, sizep, cur_proc)
int *name;
u_int namelen;
char *where;
size_t *sizep;
+ struct proc *cur_proc;
{
register struct proc *p;
register int needed = 0;
*/
pid = name[0];
+ restart:
p = pfind(pid);
if (p == NULL) {
return(EINVAL);
if (!p->user_stack)
return(EINVAL);
+ if ((p->p_ucred->cr_uid != cur_proc->p_ucred->cr_uid)
+ && suser(cur_proc->p_ucred, &cur_proc->p_acflag))
+ return (EINVAL);
arg_addr = (vm_offset_t)(p->user_stack - arg_size);
if (task == NULL)
return(EINVAL);
- task_reference(task);
+ /*
+ * A regular task_reference call can block, causing the funnel
+ * to be dropped and allowing the proc/task to get freed.
+ * Instead, we issue a non-blocking attempt at the task reference,
+ * and look up the proc/task all over again if that fails.
+ */
+ if (!task_reference_try(task)) {
+ mutex_pause();
+ goto restart;
+ }
ret = kmem_alloc(kernel_map, ©_start, round_page(arg_size));
if (ret != KERN_SUCCESS) {