Makes "measure kill" work with the appserver
[akaros.git] / kern / src / monitor.c
1 // Simple command-line kernel monitor useful for
2 // controlling the kernel and exploring the system interactively.
3
4 #ifdef __SHARC__
5 #pragma nosharc
6 #endif
7
8 #include <arch/arch.h>
9 #include <stab.h>
10 #include <smp.h>
11 #include <arch/console.h>
12
13 #include <stdio.h>
14 #include <string.h>
15 #include <assert.h>
16 #include <monitor.h>
17 #include <trap.h>
18 #include <pmap.h>
19 #include <kdebug.h>
20 #include <testing.h>
21 #include <kfs.h>
22 #include <manager.h>
23 #include <schedule.h>
24 #include <resource.h>
25 #include <kdebug.h>
26 #include <syscall.h>
27 #include <kmalloc.h>
28
29 #include <ros/timer.h>
30 #include <ros/memlayout.h>
31
32 #define CMDBUF_SIZE     80      // enough for one VGA text line
33
34 typedef struct command {
35         const char *NTS name;
36         const char *NTS desc;
37         // return -1 to force monitor to exit
38         int (*func)(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf);
39 } command_t;
40
41 static command_t (RO commands)[] = {
42         { "help", "Display this list of commands", mon_help },
43         { "kerninfo", "Display information about the kernel", mon_kerninfo },
44         { "backtrace", "Dump a backtrace", mon_backtrace },
45         { "reboot", "Take a ride to the South Bay", mon_reboot },
46         { "showmapping", "Shows VA->PA mappings", mon_showmapping},
47         { "setmapperm", "Sets permissions on a VA->PA mapping", mon_setmapperm},
48         { "cpuinfo", "Prints CPU diagnostics", mon_cpuinfo},
49         { "ps", "Prints process list", mon_ps},
50         { "nanwan", "Meet Nanwan!!", mon_nanwan},
51         { "kfs_ls", "List files in KFS", mon_kfs_ls},
52         { "kfs_run", "Create and run a program from KFS", mon_kfs_run},
53         { "kfs_cat", "Dumps text from a file from KFS", mon_kfs_cat},
54         { "manager", "Run the manager", mon_manager},
55         { "procinfo", "Show information about processes", mon_procinfo},
56         { "exit", "Leave the monitor", mon_exit},
57         { "kfunc", "Run a kernel function directly (!!!)", mon_kfunc},
58         { "notify", "Notify a process.  Vcoreid will skip their prefs", mon_notify},
59         { "measure", "Run a specific measurement", mon_measure},
60         { "trace", "Run a specific measurement", mon_trace},
61 };
62 #define NCOMMANDS (sizeof(commands)/sizeof(commands[0]))
63
64 /***** Implementations of basic kernel monitor commands *****/
65
66 int mon_help(int argc, char **argv, trapframe_t *tf)
67 {
68         int i;
69
70         for (i = 0; i < NCOMMANDS; i++)
71                 cprintf("%s - %s\n", commands[i].name, commands[i].desc);
72         return 0;
73 }
74
75 int mon_ps(int argc, char** argv, trapframe_t *tf)
76 {
77         print_allpids();
78         return 0;
79 }
80
81 int mon_kerninfo(int argc, char **argv, trapframe_t *tf)
82 {
83         extern char (RO SNT _start)[], (RO SNT etext)[], (RO SNT edata)[], (RO SNT end)[];
84
85         cprintf("Special kernel symbols:\n");
86         cprintf("  _start %08x (virt)  %08x (phys)\n", _start, (uint32_t)(_start - KERNBASE));
87         cprintf("  etext  %08x (virt)  %08x (phys)\n", etext, (uint32_t)(etext - KERNBASE));
88         cprintf("  edata  %08x (virt)  %08x (phys)\n", edata, (uint32_t)(edata - KERNBASE));
89         cprintf("  end    %08x (virt)  %08x (phys)\n", end, (uint32_t)(end - KERNBASE));
90         cprintf("Kernel executable memory footprint: %dKB\n",
91                 (uint32_t)(end-_start+1023)/1024);
92         return 0;
93 }
94
95 #if 0
96 zra: not called
97 static char RO* function_of(uint32_t address)
98 {
99         extern stab_t (RO stab)[], (RO estab)[];
100         extern char (RO stabstr)[];
101         stab_t* symtab;
102         stab_t* best_symtab = 0;
103         uint32_t best_func = 0;
104
105         // ugly and unsorted
106         for (symtab = stab; symtab < estab; symtab++) {
107                 // only consider functions, type = N_FUN
108                 if ((symtab->n_type == N_FUN) &&
109                     (symtab->n_value <= address) &&
110                         (symtab->n_value > best_func)) {
111                         best_func = symtab->n_value;
112                         best_symtab = symtab;
113                 }
114         }
115         // maybe the first stab really is the right one...  we'll see.
116         if (best_symtab == 0)
117                 return "Function not found!";
118         return stabstr + best_symtab->n_strx;
119 }
120 #endif
121
122 int mon_backtrace(int argc, char **argv, trapframe_t *tf)
123 {
124         backtrace();
125         return 0;
126 }
127
128 int mon_reboot(int argc, char **argv, trapframe_t *tf)
129 {
130         cprintf("[Scottish Accent]: She's goin' down, Cap'n!\n");
131         reboot();
132
133         // really, should never see this
134         cprintf("Sigh....\n");
135         return 0;
136 }
137
138 int mon_showmapping(int argc, char **argv, trapframe_t *tf)
139 {
140         if (argc < 2) {
141                 cprintf("Shows virtual -> physical mappings for a virtual address range.\n");
142                 cprintf("Usage: showmapping START_ADDR [END_ADDR]\n");
143                 return 1;
144         }
145         pde_t* pgdir = (pde_t*)vpd;
146         pte_t *pte, *pde;
147         page_t* page;
148         uintptr_t start, i;
149         size_t size;
150         start = ROUNDDOWN(strtol(argv[1], 0, 16), PGSIZE);
151         size = (argc == 2) ? 1 : strtol(argv[2], 0, 16) - start;
152         if (size/PGSIZE > 512) {
153                 cprintf("Not going to do this for more than 512 items\n");
154                 return 1;
155         }
156
157         show_mapping(start,size);
158         return 0;
159 }
160
161 int mon_setmapperm(int argc, char **argv, trapframe_t *tf)
162 {
163 #ifndef __i386__
164         cprintf("I don't support this call yet!\n");
165         return 1;
166 #else
167         if (argc < 3) {
168                 cprintf("Sets VIRT_ADDR's mapping's permissions to PERMS (in hex)\n");
169                 cprintf("Only affects the lowest level PTE.  To adjust the PDE, do the math.\n");
170                 cprintf("Be careful with this around UVPT, VPT, and friends.\n");
171                 cprintf("Usage: setmapperm VIRT_ADDR PERMS\n");
172                 return 1;
173         }
174         pde_t*COUNT(PTSIZE) pgdir = (pde_t*COUNT(PTSIZE))vpd;
175         pte_t *pte, *pde;
176         page_t* page;
177         uintptr_t va;
178         va = ROUNDDOWN(strtol(argv[1], 0, 16), PGSIZE);
179         page = page_lookup(pgdir, (void*SNT)va, &pte);
180         if (!page) {
181                 cprintf("No such mapping\n");
182                 return 1;
183         }
184         pde = &pgdir[PDX(va)];
185         cprintf("   Virtual    Physical  Ps Dr Ac CD WT U W\n");
186         cprintf("------------------------------------------\n");
187         cprintf("%08p  %08p  %1d  %1d  %1d  %1d  %1d  %1d %1d\n", va, page2pa(page),
188                (*pte & PTE_PS) >> 7, (*pte & PTE_D) >> 6, (*pte & PTE_A) >> 5,
189                (*pte & PTE_PCD) >> 4, (*pte & PTE_PWT) >> 3, (*pte & *pde & PTE_U) >> 2,
190                (*pte & *pde & PTE_W) >> 1);
191         *pte = PTE_ADDR(*pte) | (*pte & PTE_PS) |
192                (PGOFF(strtol(argv[2], 0, 16)) & ~PTE_PS ) | PTE_P;
193         cprintf("%08p  %08p  %1d  %1d  %1d  %1d  %1d  %1d %1d\n", va, page2pa(page),
194                (*pte & PTE_PS) >> 7, (*pte & PTE_D) >> 6, (*pte & PTE_A) >> 5,
195                (*pte & PTE_PCD) >> 4, (*pte & PTE_PWT) >> 3, (*pte & *pde & PTE_U) >> 2,
196                (*pte & *pde & PTE_W) >> 1);
197         return 0;
198 #endif
199 }
200
201 int mon_cpuinfo(int argc, char **argv, trapframe_t *tf)
202 {
203         cprintf("Number of CPUs detected: %d\n", num_cpus);
204         cprintf("Calling CPU's ID: 0x%08x\n", core_id());
205
206         if (argc < 2)
207                 smp_call_function_self(test_print_info_handler, NULL, 0);
208         else
209                 smp_call_function_single(strtol(argv[1], 0, 10),
210                                          test_print_info_handler, NULL, 0);
211         return 0;
212 }
213
214 int mon_manager(int argc, char** argv, trapframe_t *tf)
215 {
216         manager();
217         panic("should never get here");
218         return 0;
219 }
220
221 int mon_nanwan(int argc, char **argv, trapframe_t *tf)
222 {
223         /* Borrowed with love from http://www.geocities.com/SoHo/7373/zoo.htm
224          * (http://www.ascii-art.com/).  Slightly modified to make it 25 lines tall.
225          */
226         printk("\n");
227         printk("             .-.  .-.\n");
228         printk("             |  \\/  |\n");
229         printk("            /,   ,_  `'-.\n");
230         printk("          .-|\\   /`\\     '. \n");
231         printk("        .'  0/   | 0\\  \\_  `\".  \n");
232         printk("     .-'  _,/    '--'.'|#''---'\n");
233         printk("      `--'  |       /   \\#\n");
234         printk("            |      /     \\#\n");
235         printk("            \\     ;|\\    .\\#\n");
236         printk("            |' ' //  \\   ::\\# \n");
237         printk("            \\   /`    \\   ':\\#\n");
238         printk("             `\"`       \\..   \\#\n");
239         printk("                        \\::.  \\#\n");
240         printk("                         \\::   \\#\n");
241         printk("                          \\'  .:\\#\n");
242         printk("                           \\  :::\\#\n");
243         printk("                            \\  '::\\#\n");
244         printk("                             \\     \\#\n");
245         printk("                              \\:.   \\#\n");
246         printk("                               \\::   \\#\n");
247         printk("                                \\'   .\\#\n");
248         printk("                             jgs \\   ::\\#\n");
249         printk("                                  \\      \n");
250         return 0;
251 }
252
253 int mon_kfs_ls(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
254 {
255         printk("Files in KFS:\n-------------------------------\n");
256         for (int i = 0; i < MAX_KFS_FILES; i++)
257                 if (kfs[i].name[0])
258                         printk("%s\n", kfs[i].name);
259         return 0;
260 }
261
262 int mon_kfs_run(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
263 {
264         if (argc != 2) {
265                 printk("Usage: kfs_run FILENAME\n");
266                 return 1;
267         }
268         int kfs_inode = kfs_lookup_path(argv[1]);
269         if (kfs_inode < 0) {
270                 printk("Bad filename!\n");
271                 return 1;
272         }
273         struct proc *p = kfs_proc_create(kfs_inode);
274         // go from PROC_CREATED->PROC_RUNNABLE_S
275         spin_lock(&p->proc_lock); // might not be necessary for a mon function
276         __proc_set_state(p, PROC_RUNNABLE_S);
277         schedule_proc(p);
278         spin_unlock(&p->proc_lock);
279         proc_decref(p, 1); // let go of the reference created in proc_create()
280         // Should never return from schedule (env_pop in there)
281         // also note you may not get the process you created, in the event there
282         // are others floating around that are runnable
283         schedule();
284         return 0;
285 }
286
287 int mon_kfs_cat(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
288 {
289         if (argc != 2) {
290                 printk("Usage: kfs_cat FILENAME\n");
291                 return 1;
292         }
293         int kfs_inode = kfs_lookup_path(argv[1]);
294         if (kfs_inode < 0) {
295                 printk("Bad filename!\n");
296                 return 1;
297         }
298         kfs_cat(kfs_inode);
299         return 0;
300 }
301
302 int mon_procinfo(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
303 {
304         if (argc < 2) {
305                 printk("Usage: procinfo OPTION\n");
306                 printk("\tidlecores: show idle core map\n");
307                 printk("\tall: show all active pids\n");
308                 printk("\trunnable: show proc_runnablelist\n");
309                 printk("\tresources: show resources wanted/granted for all procs\n");
310                 printk("\tpid NUM: show a lot of info for proc NUM\n");
311                 printk("\tunlock NUM: unlock the lock for proc NUM (OMG!!!)\n");
312                 printk("\tkill NUM: destroy proc NUM\n");
313                 return 1;
314         }
315         if (!strcmp(argv[1], "idlecores")) {
316                 print_idlecoremap();
317         } else if (!strcmp(argv[1], "all")) {
318                 print_allpids();
319         } else if (!strcmp(argv[1], "runnable")) {
320                 dump_proclist(&proc_runnablelist);
321         } else if (!strcmp(argv[1], "resources")) {
322                 print_all_resources();
323         } else if (!strcmp(argv[1], "pid")) {
324                 if (argc != 3) {
325                         printk("Give me a pid number.\n");
326                         return 1;
327                 }
328                 print_proc_info(strtol(argv[2], 0, 0));
329         } else if (!strcmp(argv[1], "unlock")) {
330                 if (argc != 3) {
331                         printk("Give me a pid number.\n");
332                         return 1;
333                 }
334                 struct proc *p = pid2proc(strtol(argv[2], 0, 0));
335                 if (!p) {
336                         printk("No such proc\n");
337                         return 1;
338                 }
339                 spin_unlock(&p->proc_lock);
340                 proc_decref(p, 1);
341         } else if (!strcmp(argv[1], "kill")) {
342                 if (argc != 3) {
343                         printk("Give me a pid number.\n");
344                         return 1;
345                 }
346                 struct proc *p = pid2proc(strtol(argv[2], 0, 0));
347                 if (!p) {
348                         printk("No such proc\n");
349                         return 1;
350                 }
351                 proc_destroy(p);
352                 proc_decref(p, 1);
353         } else {
354                 printk("Bad option\n");
355                 return 1;
356         }
357         return 0;
358 }
359
360 int mon_exit(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
361 {
362         return -1;
363 }
364
365 int mon_kfunc(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
366 {
367         #ifndef __i386__
368         printk("Only supported on x86 for now.  =(\n");
369         return -1;
370         #endif
371
372         void (*func)(void *arg, ...);
373
374         if (argc < 2) {
375                 printk("Usage: kfunc FUNCTION [arg1] [arg2] [etc]\n");
376                 printk("Arguments must be in hex.  Can take 6 args.\n");
377                 return 1;
378         }
379         func = debug_get_fn_addr(argv[1]);
380         if (!func) {
381                 printk("Function not found.\n");
382                 return 1;
383         }
384         /* Not elegant, but whatever.  maybe there's a better syntax, or we can do
385          * it with asm magic. */
386         switch (argc) {
387                 case 2: /* have to fake one arg */
388                         func((void*)0);
389                         break;
390                 case 3: /* the real first arg */
391                         func((void*)strtol(argv[2], 0, 16));
392                         break;
393                 case 4:
394                         func((void*)strtol(argv[2], 0, 16),
395                                     strtol(argv[3], 0, 16));
396                         break;
397                 case 5:
398                         func((void*)strtol(argv[2], 0, 16),
399                                     strtol(argv[3], 0, 16),
400                                     strtol(argv[4], 0, 16));
401                         break;
402                 case 6:
403                         func((void*)strtol(argv[2], 0, 16),
404                                     strtol(argv[3], 0, 16),
405                                     strtol(argv[4], 0, 16),
406                                     strtol(argv[5], 0, 16));
407                         break;
408                 case 7:
409                         func((void*)strtol(argv[2], 0, 16),
410                                     strtol(argv[3], 0, 16),
411                                     strtol(argv[4], 0, 16),
412                                     strtol(argv[5], 0, 16),
413                                     strtol(argv[6], 0, 16));
414                         break;
415                 case 8:
416                         func((void*)strtol(argv[2], 0, 16),
417                                     strtol(argv[3], 0, 16),
418                                     strtol(argv[4], 0, 16),
419                                     strtol(argv[5], 0, 16),
420                                     strtol(argv[6], 0, 16),
421                                     strtol(argv[7], 0, 16));
422                         break;
423                 default:
424                         printk("Bad number of arguments.\n");
425                         return -1;
426         }
427         return 0;
428 }
429
430 int mon_notify(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
431 {
432         struct proc *p;
433         unsigned int num;
434         uint32_t vcoreid;
435
436         if (argc < 3) {
437                 printk("Usage: notify PID NUM [VCOREID]\n");
438                 return 1;
439         }
440         p = pid2proc(strtol(argv[1], 0, 0));
441         if (!p) {
442                 printk("No such proc\n");
443                 return 1;
444         }
445         num = strtol(argv[2], 0, 0);
446         if (argc == 4) {
447                 vcoreid = strtol(argv[3], 0, 0);
448                 do_notify(p, vcoreid, num, 0);
449         } else {
450                 proc_notify(p, num, 0);
451         }
452         proc_decref(p, 1);
453         return 0;
454 }
455
456 /* Micro-benchmarky Measurements */
457 int mon_measure(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
458 {
459         uint64_t begin = 0, diff = 0;
460         bool self_ipi_pending = FALSE;
461         uint32_t end_refcnt = 0;
462
463         if (argc < 2) {
464                 printk("Usage: measure OPTION\n");
465                 printk("\tkill PID : kill proc PID\n");
466                 printk("\tpreempt PID : preempt proc PID (no delay)\n");
467                 printk("\tpreempt PID [pcore] : preempt PID's pcore (no delay)\n");
468                 printk("\tpreempt-warn PID : warn-preempt proc PID (pending)\n");
469                 printk("\tpreempt-warn PID [pcore] : warn-preempt proc PID's pcore\n");
470                 printk("\tpreempt-raw PID : raw-preempt proc PID\n");
471                 printk("\tpreempt-raw PID [pcore] : raw-preempt proc PID's pcore\n");
472                 return 1;
473         }
474         if (!strcmp(argv[1], "kill")) {
475                 if (argc < 3) {
476                         printk("Give me a pid number.\n");
477                         return 1;
478                 }
479                 struct proc *p = pid2proc(strtol(argv[2], 0, 0));
480                 if (!p) {
481                         printk("No such proc\n");
482                         return 1;
483                 }
484                 begin = start_timing();
485 #ifdef __CONFIG_APPSERVER__
486                 printk("Warning: this will be inaccurate due to the appserver.\n");
487                 end_refcnt = p->env_refcnt - p->procinfo->num_vcores - 1;
488 #endif /* __CONFIG_APPSERVER__ */
489                 proc_destroy(p);
490                 proc_decref(p, 1);
491 #ifdef __CONFIG_APPSERVER__
492                 /* Won't be that accurate, since it's not actually going through the
493                  * __proc_free() path. */
494                 spin_on(p->env_refcnt != end_refcnt);   
495 #else
496                 /* this is a little ghetto. it's not fully free yet, but we are also
497                  * slowing it down by messing with it, esp with the busy waiting on a
498                  * hyperthreaded core. */
499                 spin_on(p->env_cr3);
500 #endif /* __CONFIG_APPSERVER__ */
501                 /* No noticeable difference using stop_timing instead of read_tsc() */
502                 diff = stop_timing(begin);
503         } else if (!strcmp(argv[1], "preempt")) {
504                 if (argc < 3) {
505                         printk("Give me a pid number.\n");
506                         return 1;
507                 }
508                 struct proc *p = pid2proc(strtol(argv[2], 0, 0));
509                 if (!p) {
510                         printk("No such proc\n");
511                         return 1;
512                 }
513                 if (argc == 4) { /* single core being preempted, warned but no delay */
514                         uint32_t pcoreid = strtol(argv[3], 0, 0);
515                         begin = start_timing();
516                         proc_preempt_core(p, pcoreid, 1000000); // 1 sec warning
517                         /* done when unmapped (right before abandoning) */
518                         spin_on(p->procinfo->pcoremap[pcoreid].valid);
519                         diff = stop_timing(begin);
520                 } else { /* preempt all cores, warned but no delay */
521                         end_refcnt = p->env_refcnt - p->procinfo->num_vcores;
522                         begin = start_timing();
523                         proc_preempt_all(p, 1000000);
524                         /* a little ghetto, implies no one is using p */
525                         spin_on(p->env_refcnt != end_refcnt);
526                         diff = stop_timing(begin);
527                 }
528                 proc_decref(p, 1);
529         } else if (!strcmp(argv[1], "preempt-warn")) {
530                 if (argc < 3) {
531                         printk("Give me a pid number.\n");
532                         return 1;
533                 }
534                 struct proc *p = pid2proc(strtol(argv[2], 0, 0));
535                 if (!p) {
536                         printk("No such proc\n");
537                         return 1;
538                 }
539                 if (argc == 4) { /* single core being preempted-warned */
540                         uint32_t pcoreid = strtol(argv[3], 0, 0);
541                         spin_lock(&p->proc_lock);
542                         uint32_t vcoreid = p->procinfo->pcoremap[pcoreid].vcoreid;
543                         if (!p->procinfo->pcoremap[pcoreid].valid) {
544                                 printk("Pick a mapped pcore\n");
545                                 spin_unlock(&p->proc_lock);
546                                 return 1;
547                         }
548                         begin = start_timing();
549                         __proc_preempt_warn(p, vcoreid, 1000000); // 1 sec
550                         spin_unlock(&p->proc_lock);
551                         /* done when unmapped (right before abandoning) */
552                         spin_on(p->procinfo->pcoremap[pcoreid].valid);
553                         diff = stop_timing(begin);
554                 } else { /* preempt-warn all cores */
555                         printk("Warning, this won't work if they can't yield their "
556                                "last vcore, will stop at 1!\n");
557                         spin_lock(&p->proc_lock);
558                         begin = start_timing();
559                         __proc_preempt_warnall(p, 1000000);
560                         spin_unlock(&p->proc_lock);
561                         /* target cores do the unmapping / changing of the num_vcores */
562                         spin_on(p->procinfo->num_vcores > 1);
563                         diff = stop_timing(begin);
564                 }
565                 proc_decref(p, 1);
566         } else if (!strcmp(argv[1], "preempt-raw")) {
567                 if (argc < 3) {
568                         printk("Give me a pid number.\n");
569                         return 1;
570                 }
571                 struct proc *p = pid2proc(strtol(argv[2], 0, 0));
572                 if (!p) {
573                         printk("No such proc\n");
574                         return 1;
575                 }
576                 if (argc == 4) { /* single core preempted, no warning or waiting */
577                         uint32_t pcoreid = strtol(argv[3], 0, 0);
578                         spin_lock(&p->proc_lock);
579                         if (!p->procinfo->pcoremap[pcoreid].valid) {
580                                 printk("Pick a mapped pcore\n");
581                                 spin_unlock(&p->proc_lock);
582                                 return 1;
583                         }
584                         begin = start_timing();
585                         self_ipi_pending = __proc_preempt_core(p, pcoreid);
586                         spin_unlock(&p->proc_lock);
587                         __proc_kmsg_pending(p, self_ipi_pending);
588                         /* done when unmapped (right before abandoning) */
589                         spin_on(p->procinfo->pcoremap[pcoreid].valid);
590                         diff = stop_timing(begin);
591                         /* TODO: (RMS), if num_vcores == 0, RUNNABLE_M, schedule */
592                 } else { /* preempt all cores, no warning or waiting */
593                         spin_lock(&p->proc_lock);
594                         end_refcnt = p->env_refcnt - p->procinfo->num_vcores;
595                         begin = start_timing();
596                         self_ipi_pending = __proc_preempt_all(p);
597                         /* TODO: (RMS), RUNNABLE_M, schedule */
598                         spin_unlock(&p->proc_lock);
599                         __proc_kmsg_pending(p, self_ipi_pending);
600                         /* a little ghetto, implies no one else is using p */
601                         spin_on(p->env_refcnt != end_refcnt);
602                         diff = stop_timing(begin);
603                 }
604                 proc_decref(p, 1);
605         } else {
606                 printk("Bad option\n");
607                 return 1;
608         }
609         printk("[Tired Giraffe Accent] Took %llu usec (%llu nsec) to finish.\n",
610                diff * 1000000 / system_timing.tsc_freq,
611                diff * 1000000000 / system_timing.tsc_freq);
612         return 0;
613 }
614
615 int mon_trace(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
616 {
617         if (argc < 2) {
618                 printk("Usage: trace OPTION\n");
619                 printk("\tsyscall start [silent] [pid]: starts tracing\n");
620                 printk("\tsyscall stop: stops tracing, prints if it was silent\n");
621                 return 1;
622         }
623         if (!strcmp(argv[1], "syscall")) {
624                 if (argc < 3) {
625                         printk("Need a start or stop.\n");
626                         return 1;
627                 }
628                 if (!strcmp(argv[2], "start")) {
629                         bool all = TRUE;
630                         bool silent = FALSE;
631                         struct proc *p = NULL;
632                         if (argc >= 4) {
633                                 silent = (bool)strtol(argv[3], 0, 0);
634                         }
635                         if (argc >= 5) {
636                                 all = FALSE;
637                                 p = pid2proc(strtol(argv[4], 0, 0));
638                                 if (!p) {
639                                         printk("No such process\n");
640                                         return 1;
641                                 }
642                         }
643                         systrace_start(silent);
644                         if (systrace_reg(all, p))
645                                 printk("No room to trace more processes\n");
646                 } else if (!strcmp(argv[2], "stop")) {
647                         /* Stop and print for all processes */
648                         systrace_stop();
649                         systrace_print(TRUE, 0);
650                         systrace_clear_buffer();
651                 }
652         } else if (!strcmp(argv[1], "opt2")) {
653                 if (argc != 3) {
654                         printk("ERRRRRRRRRR.\n");
655                         return 1;
656                 }
657                 print_proc_info(strtol(argv[2], 0, 0));
658         } else {
659                 printk("Bad option\n");
660                 return 1;
661         }
662         return 0;
663 }
664
665 /***** Kernel monitor command interpreter *****/
666
667 #define WHITESPACE "\t\r\n "
668 #define MAXARGS 16
669
670 static int runcmd(char *NTS real_buf, trapframe_t *tf) {
671         char * buf = NTEXPAND(real_buf);
672         int argc;
673         char *NTS argv[MAXARGS];
674         int i;
675
676         // Parse the command buffer into whitespace-separated arguments
677         argc = 0;
678         argv[argc] = 0;
679         while (1) {
680                 // gobble whitespace
681                 while (*buf && strchr(WHITESPACE, *buf))
682                         *buf++ = 0;
683                 if (*buf == 0)
684                         break;
685
686                 // save and scan past next arg
687                 if (argc == MAXARGS-1) {
688                         cprintf("Too many arguments (max %d)\n", MAXARGS);
689                         return 0;
690                 }
691                 //This will get fucked at runtime..... in the ASS
692                 argv[argc++] = buf;
693                 while (*buf && !strchr(WHITESPACE, *buf))
694                         buf++;
695         }
696         argv[argc] = 0;
697
698         // Lookup and invoke the command
699         if (argc == 0)
700                 return 0;
701         for (i = 0; i < NCOMMANDS; i++) {
702                 if (strcmp(argv[0], commands[i].name) == 0)
703                         return commands[i].func(argc, argv, tf);
704         }
705         cprintf("Unknown command '%s'\n", argv[0]);
706         return 0;
707 }
708
709 void monitor(trapframe_t *tf) {
710         static spinlock_t monitor_lock = SPINLOCK_INITIALIZER;
711         spin_lock_irqsave(&monitor_lock);
712
713         char *buf;
714
715         printk("Welcome to the ROS kernel monitor on core %d!\n", core_id());
716         printk("Type 'help' for a list of commands.\n");
717
718         if (tf != NULL)
719                 print_trapframe(tf);
720
721         spin_unlock_irqsave(&monitor_lock);
722         while (1) {
723                 spin_lock_irqsave(&monitor_lock);
724                 buf = readline("K> ");
725                 if (buf != NULL) {
726                         spin_unlock_irqsave(&monitor_lock);
727                         if (runcmd(buf, tf) < 0)
728                                 break;
729                 }
730         }
731 }