vm: util.S not used currently; leave it out.
[minix.git] / servers / pm / misc.c
blobb5c7c0595a01176a6232bd15ad2ce6b89d48818b
1 /* Miscellaneous system calls. Author: Kees J. Bot
2 * 31 Mar 2000
3 * The entry points into this file are:
4 * do_reboot: kill all processes, then reboot system
5 * do_procstat: request process status (Jorrit N. Herder)
6 * do_getsysinfo: request copy of PM data structure (Jorrit N. Herder)
7 * do_getprocnr: lookup process slot number (Jorrit N. Herder)
8 * do_getepinfo: get the pid/uid/gid of a process given its endpoint
9 * do_getsetpriority: get/set process priority
10 * do_svrctl: process manager control
13 #define brk _brk
15 #include "pm.h"
16 #include <minix/callnr.h>
17 #include <signal.h>
18 #include <sys/svrctl.h>
19 #include <sys/resource.h>
20 #include <sys/utsname.h>
21 #include <minix/com.h>
22 #include <minix/config.h>
23 #include <minix/sysinfo.h>
24 #include <minix/type.h>
25 #include <minix/vm.h>
26 #include <string.h>
27 #include <machine/archtypes.h>
28 #include <lib.h>
29 #include <assert.h>
30 #include "mproc.h"
31 #include "param.h"
32 #include "kernel/proc.h"
34 PUBLIC struct utsname uts_val = {
35 "Minix", /* system name */
36 "noname", /* node/network name */
37 OS_RELEASE, /* O.S. release (e.g. 1.5) */
38 OS_VERSION, /* O.S. version (e.g. 10) */
39 "xyzzy", /* machine (cpu) type (filled in later) */
40 #if __i386
41 "i386", /* architecture */
42 #else
43 #error /* oops, no 'uname -mk' */
44 #endif
47 PRIVATE char *uts_tbl[] = {
48 uts_val.arch,
49 NULL, /* No kernel architecture */
50 uts_val.machine,
51 NULL, /* No hostname */
52 uts_val.nodename,
53 uts_val.release,
54 uts_val.version,
55 uts_val.sysname,
56 NULL, /* No bus */ /* No bus */
59 #if ENABLE_SYSCALL_STATS
60 PUBLIC unsigned long calls_stats[NCALLS];
61 #endif
63 FORWARD _PROTOTYPE( int getpciinfo, (struct pciinfo *pciinfo) );
65 /*===========================================================================*
66 * do_procstat *
67 *===========================================================================*/
68 PUBLIC int do_procstat()
70 /* For the moment, this is only used to return pending signals to
71 * system processes that request the PM for their own status.
73 * Future use might include the FS requesting for process status of
74 * any user process.
77 /* This call should be removed, or made more general. */
79 if (m_in.stat_nr == SELF) {
80 mp->mp_reply.sig_set = mp->mp_sigpending;
81 sigemptyset(&mp->mp_sigpending);
83 else {
84 return(ENOSYS);
86 return(OK);
89 /*===========================================================================*
90 * do_sysuname *
91 *===========================================================================*/
92 PUBLIC int do_sysuname()
94 /* Set or get uname strings. */
96 int r;
97 size_t n;
98 char *string;
99 #if 0 /* for updates */
100 char tmp[sizeof(uts_val.nodename)];
101 static short sizes[] = {
102 0, /* arch, (0 = read-only) */
103 0, /* kernel */
104 0, /* machine */
105 0, /* sizeof(uts_val.hostname), */
106 sizeof(uts_val.nodename),
107 0, /* release */
108 0, /* version */
109 0, /* sysname */
111 #endif
113 if ((unsigned) m_in.sysuname_field >= _UTS_MAX) return(EINVAL);
115 string = uts_tbl[m_in.sysuname_field];
116 if (string == NULL)
117 return EINVAL; /* Unsupported field */
119 switch (m_in.sysuname_req) {
120 case _UTS_GET:
121 /* Copy an uname string to the user. */
122 n = strlen(string) + 1;
123 if (n > m_in.sysuname_len) n = m_in.sysuname_len;
124 r = sys_vircopy(SELF, D, (phys_bytes) string,
125 mp->mp_endpoint, D, (phys_bytes) m_in.sysuname_value,
126 (phys_bytes) n);
127 if (r < 0) return(r);
128 break;
130 #if 0 /* no updates yet */
131 case _UTS_SET:
132 /* Set an uname string, needs root power. */
133 len = sizes[m_in.sysuname_field];
134 if (mp->mp_effuid != 0 || len == 0) return(EPERM);
135 n = len < m_in.sysuname_len ? len : m_in.sysuname_len;
136 if (n <= 0) return(EINVAL);
137 r = sys_vircopy(mp->mp_endpoint, D, (phys_bytes) m_in.sysuname_value,
138 SELF, D, (phys_bytes) tmp, (phys_bytes) n);
139 if (r < 0) return(r);
140 tmp[n-1] = 0;
141 strcpy(string, tmp);
142 break;
143 #endif
145 default:
146 return(EINVAL);
148 /* Return the number of bytes moved. */
149 return(n);
153 /*===========================================================================*
154 * do_getsysinfo *
155 *===========================================================================*/
156 PUBLIC int do_getsysinfo()
158 struct mproc *proc_addr;
159 vir_bytes src_addr, dst_addr;
160 struct kinfo kinfo;
161 struct loadinfo loadinfo;
162 struct pciinfo pciinfo;
163 static struct proc proctab[NR_PROCS+NR_TASKS];
164 size_t len;
165 int s, r;
167 /* This call leaks important information (the contents of registers). */
168 if (mp->mp_effuid != 0)
170 printf("PM: unauthorized call of do_getsysinfo by proc %d '%s'\n",
171 mp->mp_endpoint, mp->mp_name);
172 sys_sysctl_stacktrace(mp->mp_endpoint);
173 return EPERM;
176 switch(m_in.info_what) {
177 case SI_KINFO: /* kernel info is obtained via PM */
178 sys_getkinfo(&kinfo);
179 src_addr = (vir_bytes) &kinfo;
180 len = sizeof(struct kinfo);
181 break;
182 case SI_PROC_ADDR: /* get address of PM process table */
183 proc_addr = &mproc[0];
184 src_addr = (vir_bytes) &proc_addr;
185 len = sizeof(struct mproc *);
186 break;
187 case SI_PROC_TAB: /* copy entire process table */
188 src_addr = (vir_bytes) mproc;
189 len = sizeof(struct mproc) * NR_PROCS;
190 break;
191 case SI_KPROC_TAB: /* copy entire process table */
192 if((r=sys_getproctab(proctab)) != OK)
193 return r;
194 src_addr = (vir_bytes) proctab;
195 len = sizeof(proctab);
196 break;
197 case SI_LOADINFO: /* loadinfo is obtained via PM */
198 sys_getloadinfo(&loadinfo);
199 src_addr = (vir_bytes) &loadinfo;
200 len = sizeof(struct loadinfo);
201 break;
202 case SI_PCI_INFO: /* PCI info is obtained via PM */
203 if ((r=getpciinfo(&pciinfo)) != OK)
204 return r;
205 src_addr = (vir_bytes) &pciinfo;
206 len = sizeof(struct pciinfo);
207 break;
208 #if ENABLE_SYSCALL_STATS
209 case SI_CALL_STATS:
210 src_addr = (vir_bytes) calls_stats;
211 len = sizeof(calls_stats);
212 break;
213 #endif
214 default:
215 return(EINVAL);
218 dst_addr = (vir_bytes) m_in.info_where;
219 if (OK != (s=sys_datacopy(SELF, src_addr, who_e, dst_addr, len)))
220 return(s);
221 return(OK);
224 /*===========================================================================*
225 * do_getsysinfo_up *
226 *===========================================================================*/
227 PUBLIC int do_getsysinfo_up()
229 vir_bytes src_addr, dst_addr;
230 struct loadinfo loadinfo;
231 size_t len, real_len;
232 u64_t idle_tsc;
233 int s;
235 switch(m_in.SIU_WHAT) {
236 case SIU_LOADINFO: /* loadinfo is obtained via PM */
237 if ((s = sys_getloadinfo(&loadinfo)) != OK)
238 return s;
239 src_addr = (vir_bytes) &loadinfo;
240 real_len = sizeof(struct loadinfo);
241 break;
242 case SIU_SYSTEMHZ:
243 src_addr = (vir_bytes) &system_hz;
244 real_len = sizeof(system_hz);
245 break;
246 case SIU_IDLETSC:
247 if ((s = sys_getidletsc(&idle_tsc)) != OK)
248 return s;
249 src_addr = (vir_bytes) &idle_tsc;
250 real_len = sizeof(idle_tsc);
251 break;
252 default:
253 return(EINVAL);
256 /* Let application know what the length was. */
257 len = real_len;
258 if(len > m_in.SIU_LEN)
259 len = m_in.SIU_LEN;
261 dst_addr = (vir_bytes) m_in.SIU_WHERE;
262 if (OK != (s=sys_datacopy(SELF, src_addr, who_e, dst_addr, len)))
263 return(s);
264 return(real_len);
267 /*===========================================================================*
268 * do_getprocnr *
269 *===========================================================================*/
270 PUBLIC int do_getprocnr()
272 register struct mproc *rmp;
273 static char search_key[PROC_NAME_LEN+1];
274 int key_len;
275 int s;
277 /* This call should be moved to DS. */
278 if (mp->mp_effuid != 0)
280 /* For now, allow non-root processes to request their own endpoint. */
281 if (m_in.pid < 0 && m_in.namelen == 0) {
282 mp->mp_reply.PM_ENDPT = who_e;
283 mp->mp_reply.PM_PENDPT = NONE;
284 return OK;
287 printf("PM: unauthorized call of do_getprocnr by proc %d\n",
288 mp->mp_endpoint);
289 sys_sysctl_stacktrace(mp->mp_endpoint);
290 return EPERM;
293 #if 0
294 printf("PM: do_getprocnr(%d) call from endpoint %d, %s\n",
295 m_in.pid, mp->mp_endpoint, mp->mp_name);
296 #endif
298 if (m_in.pid >= 0) { /* lookup process by pid */
299 if ((rmp = find_proc(m_in.pid)) != NIL_MPROC) {
300 mp->mp_reply.PM_ENDPT = rmp->mp_endpoint;
301 #if 0
302 printf("PM: pid result: %d\n", rmp->mp_endpoint);
303 #endif
304 return(OK);
306 return(ESRCH);
307 } else if (m_in.namelen > 0) { /* lookup process by name */
308 key_len = MIN(m_in.namelen, PROC_NAME_LEN);
309 if (OK != (s=sys_datacopy(who_e, (vir_bytes) m_in.PMBRK_ADDR,
310 SELF, (vir_bytes) search_key, key_len)))
311 return(s);
312 search_key[key_len] = '\0'; /* terminate for safety */
313 for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
314 if (((rmp->mp_flags & (IN_USE | EXITING)) == IN_USE) &&
315 strncmp(rmp->mp_name, search_key, key_len)==0) {
316 mp->mp_reply.PM_ENDPT = rmp->mp_endpoint;
317 return(OK);
320 return(ESRCH);
321 } else { /* return own/parent process number */
322 #if 0
323 printf("PM: endpt result: %d\n", mp->mp_reply.PM_ENDPT);
324 #endif
325 mp->mp_reply.PM_ENDPT = who_e;
326 mp->mp_reply.PM_PENDPT = mproc[mp->mp_parent].mp_endpoint;
329 return(OK);
332 /*===========================================================================*
333 * do_getepinfo *
334 *===========================================================================*/
335 PUBLIC int do_getepinfo()
337 register struct mproc *rmp;
338 endpoint_t ep;
340 /* This call should be moved to DS. */
341 if (mp->mp_effuid != 0)
343 printf("PM: unauthorized call of do_getepinfo by proc %d\n",
344 mp->mp_endpoint);
345 sys_sysctl_stacktrace(mp->mp_endpoint);
346 return EPERM;
349 ep= m_in.PM_ENDPT;
351 for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
352 if ((rmp->mp_flags & IN_USE) && (rmp->mp_endpoint == ep)) {
353 mp->mp_reply.reply_res2 = rmp->mp_effuid;
354 mp->mp_reply.reply_res3 = rmp->mp_effgid;
355 return(rmp->mp_pid);
359 /* Process not found */
360 return(ESRCH);
363 /*===========================================================================*
364 * do_reboot *
365 *===========================================================================*/
366 PUBLIC int do_reboot()
368 message m;
370 /* Check permission to abort the system. */
371 if (mp->mp_effuid != SUPER_USER) return(EPERM);
373 /* See how the system should be aborted. */
374 abort_flag = (unsigned) m_in.reboot_flag;
375 if (abort_flag >= RBT_INVALID) return(EINVAL);
376 if (RBT_MONITOR == abort_flag) {
377 int r;
378 if(m_in.reboot_strlen >= sizeof(monitor_code))
379 return EINVAL;
380 if((r = sys_datacopy(who_e, (vir_bytes) m_in.reboot_code,
381 SELF, (vir_bytes) monitor_code, m_in.reboot_strlen)) != OK)
382 return r;
383 monitor_code[m_in.reboot_strlen] = '\0';
385 else
386 monitor_code[0] = '\0';
388 /* Order matters here. When FS is told to reboot, it exits all its
389 * processes, and then would be confused if they're exited again by
390 * SIGKILL. So first kill, then reboot.
393 check_sig(-1, SIGKILL, FALSE /* ksig*/); /* kill all users except init */
394 sys_stop(INIT_PROC_NR); /* stop init, but keep it around */
396 /* Tell FS to reboot */
397 m.m_type = PM_REBOOT;
399 tell_fs(&mproc[FS_PROC_NR], &m);
401 return(SUSPEND); /* don't reply to caller */
404 /*===========================================================================*
405 * do_getsetpriority *
406 *===========================================================================*/
407 PUBLIC int do_getsetpriority()
409 int r, arg_which, arg_who, arg_pri, new_q;
410 struct mproc *rmp;
412 arg_which = m_in.m1_i1;
413 arg_who = m_in.m1_i2;
414 arg_pri = m_in.m1_i3; /* for SETPRIORITY */
416 /* Code common to GETPRIORITY and SETPRIORITY. */
418 /* Only support PRIO_PROCESS for now. */
419 if (arg_which != PRIO_PROCESS)
420 return(EINVAL);
422 if (arg_who == 0)
423 rmp = mp;
424 else
425 if ((rmp = find_proc(arg_who)) == NIL_MPROC)
426 return(ESRCH);
428 if (mp->mp_effuid != SUPER_USER &&
429 mp->mp_effuid != rmp->mp_effuid && mp->mp_effuid != rmp->mp_realuid)
430 return EPERM;
432 /* If GET, that's it. */
433 if (call_nr == GETPRIORITY) {
434 return(rmp->mp_nice - PRIO_MIN);
437 /* Only root is allowed to reduce the nice level. */
438 if (rmp->mp_nice > arg_pri && mp->mp_effuid != SUPER_USER)
439 return(EACCES);
441 /* We're SET, and it's allowed.
443 * The value passed in is currently between PRIO_MIN and PRIO_MAX.
444 * We have to scale this between MIN_USER_Q and MAX_USER_Q to match
445 * the kernel's scheduling queues.
447 * TODO: This assumes that we are the scheduler, this will be changed
448 * once the scheduler gets factored out of PM to its own server
450 if (arg_pri < PRIO_MIN || arg_pri > PRIO_MAX) return(EINVAL);
452 new_q = MAX_USER_Q + (arg_pri-PRIO_MIN) * (MIN_USER_Q-MAX_USER_Q+1) /
453 (PRIO_MAX-PRIO_MIN+1);
454 if (new_q < MAX_USER_Q) new_q = MAX_USER_Q; /* shouldn't happen */
455 if (new_q > MIN_USER_Q) new_q = MIN_USER_Q; /* shouldn't happen */
457 rmp->mp_max_priority = rmp->mp_priority = new_q;
458 if ((r = schedule_process(rmp)))
459 return(r);
461 rmp->mp_nice = arg_pri;
462 return(OK);
465 /*===========================================================================*
466 * do_svrctl *
467 *===========================================================================*/
468 PUBLIC int do_svrctl()
470 int s, req;
471 vir_bytes ptr;
472 #define MAX_LOCAL_PARAMS 2
473 static struct {
474 char name[30];
475 char value[30];
476 } local_param_overrides[MAX_LOCAL_PARAMS];
477 static int local_params = 0;
479 req = m_in.svrctl_req;
480 ptr = (vir_bytes) m_in.svrctl_argp;
482 /* Is the request indeed for the MM? */
483 if (((req >> 8) & 0xFF) != 'M') return(EINVAL);
485 /* Control operations local to the PM. */
486 switch(req) {
487 case MMSETPARAM:
488 case MMGETPARAM: {
489 struct sysgetenv sysgetenv;
490 char search_key[64];
491 char *val_start;
492 size_t val_len;
493 size_t copy_len;
495 /* Copy sysgetenv structure to PM. */
496 if (sys_datacopy(who_e, ptr, SELF, (vir_bytes) &sysgetenv,
497 sizeof(sysgetenv)) != OK) return(EFAULT);
499 /* Set a param override? */
500 if (req == MMSETPARAM) {
501 if (local_params >= MAX_LOCAL_PARAMS) return ENOSPC;
502 if (sysgetenv.keylen <= 0
503 || sysgetenv.keylen >=
504 sizeof(local_param_overrides[local_params].name)
505 || sysgetenv.vallen <= 0
506 || sysgetenv.vallen >=
507 sizeof(local_param_overrides[local_params].value))
508 return EINVAL;
510 if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.key,
511 SELF, (vir_bytes) local_param_overrides[local_params].name,
512 sysgetenv.keylen)) != OK)
513 return s;
514 if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.val,
515 SELF, (vir_bytes) local_param_overrides[local_params].value,
516 sysgetenv.vallen)) != OK)
517 return s;
518 local_param_overrides[local_params].name[sysgetenv.keylen] = '\0';
519 local_param_overrides[local_params].value[sysgetenv.vallen] = '\0';
521 local_params++;
523 return OK;
526 if (sysgetenv.keylen == 0) { /* copy all parameters */
527 val_start = monitor_params;
528 val_len = sizeof(monitor_params);
530 else { /* lookup value for key */
531 int p;
532 /* Try to get a copy of the requested key. */
533 if (sysgetenv.keylen > sizeof(search_key)) return(EINVAL);
534 if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.key,
535 SELF, (vir_bytes) search_key, sysgetenv.keylen)) != OK)
536 return(s);
538 /* Make sure key is null-terminated and lookup value.
539 * First check local overrides.
541 search_key[sysgetenv.keylen-1]= '\0';
542 for(p = 0; p < local_params; p++) {
543 if (!strcmp(search_key, local_param_overrides[p].name)) {
544 val_start = local_param_overrides[p].value;
545 break;
548 if (p >= local_params && (val_start = find_param(search_key)) == NULL)
549 return(ESRCH);
550 val_len = strlen(val_start) + 1;
553 /* See if it fits in the client's buffer. */
554 if (val_len > sysgetenv.vallen)
555 return E2BIG;
557 /* Value found, make the actual copy (as far as possible). */
558 copy_len = MIN(val_len, sysgetenv.vallen);
559 if ((s=sys_datacopy(SELF, (vir_bytes) val_start,
560 who_e, (vir_bytes) sysgetenv.val, copy_len)) != OK)
561 return(s);
563 return OK;
566 default:
567 return(EINVAL);
571 /*===========================================================================*
572 * _brk *
573 *===========================================================================*/
575 extern char *_brksize;
576 PUBLIC int brk(brk_addr)
577 char *brk_addr;
579 int r;
580 /* PM wants to call brk() itself. */
581 if((r=vm_brk(PM_PROC_NR, brk_addr)) != OK) {
582 #if 0
583 printf("PM: own brk(%p) failed: vm_brk() returned %d\n",
584 brk_addr, r);
585 #endif
586 return -1;
588 _brksize = brk_addr;
589 return 0;
592 /*===========================================================================*
593 * getpciinfo *
594 *===========================================================================*/
596 PRIVATE int getpciinfo(pciinfo)
597 struct pciinfo *pciinfo;
599 int devind, r;
600 struct pciinfo_entry *entry;
601 char *name;
602 u16_t vid, did;
604 /* look up PCI process number */
605 pci_init();
607 /* start enumerating devices */
608 entry = pciinfo->pi_entries;
609 r = pci_first_dev(&devind, &vid, &did);
610 while (r)
612 /* fetch device name */
613 name = pci_dev_name(vid, did);
614 if (!name)
615 name = "";
617 /* store device information in table */
618 assert((char *) entry < (char *) (pciinfo + 1));
619 entry->pie_vid = vid;
620 entry->pie_did = did;
621 strncpy(entry->pie_name, name, sizeof(entry->pie_name));
622 entry->pie_name[sizeof(entry->pie_name) - 1] = 0;
623 entry++;
625 /* continue with the next device */
626 r = pci_next_dev(&devind, &vid, &did);
629 /* store number of entries */
630 pciinfo->pi_count = entry - pciinfo->pi_entries;
631 return OK;