Monitor function to notify a proc
[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
27 #include <ros/memlayout.h>
28
29 #define CMDBUF_SIZE     80      // enough for one VGA text line
30
31 typedef struct command {
32         const char *NTS name;
33         const char *NTS desc;
34         // return -1 to force monitor to exit
35         int (*func)(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf);
36 } command_t;
37
38 static command_t (RO commands)[] = {
39         { "help", "Display this list of commands", mon_help },
40         { "kerninfo", "Display information about the kernel", mon_kerninfo },
41         { "backtrace", "Dump a backtrace", mon_backtrace },
42         { "reboot", "Take a ride to the South Bay", mon_reboot },
43         { "showmapping", "Shows VA->PA mappings", mon_showmapping},
44         { "setmapperm", "Sets permissions on a VA->PA mapping", mon_setmapperm},
45         { "cpuinfo", "Prints CPU diagnostics", mon_cpuinfo},
46         { "ps", "Prints process list", mon_ps},
47         { "nanwan", "Meet Nanwan!!", mon_nanwan},
48         { "kfs_ls", "List files in KFS", mon_kfs_ls},
49         { "kfs_run", "Create and run a program from KFS", mon_kfs_run},
50         { "kfs_cat", "Dumps text from a file from KFS", mon_kfs_cat},
51         { "manager", "Run the manager", mon_manager},
52         { "procinfo", "Show information about processes", mon_procinfo},
53         { "exit", "Leave the monitor", mon_exit},
54         { "kfunc", "Run a kernel function directly (!!!)", mon_kfunc},
55         { "notify", "Notify a process.  Vcoreid will skip their prefs", mon_notify},
56 };
57 #define NCOMMANDS (sizeof(commands)/sizeof(commands[0]))
58
59 /***** Implementations of basic kernel monitor commands *****/
60
61 int mon_help(int argc, char **argv, trapframe_t *tf)
62 {
63         int i;
64
65         for (i = 0; i < NCOMMANDS; i++)
66                 cprintf("%s - %s\n", commands[i].name, commands[i].desc);
67         return 0;
68 }
69
70 int mon_ps(int argc, char** argv, trapframe_t *tf)
71 {
72         print_allpids();
73         return 0;
74 }
75
76 int mon_kerninfo(int argc, char **argv, trapframe_t *tf)
77 {
78         extern char (RO SNT _start)[], (RO SNT etext)[], (RO SNT edata)[], (RO SNT end)[];
79
80         cprintf("Special kernel symbols:\n");
81         cprintf("  _start %08x (virt)  %08x (phys)\n", _start, (uint32_t)(_start - KERNBASE));
82         cprintf("  etext  %08x (virt)  %08x (phys)\n", etext, (uint32_t)(etext - KERNBASE));
83         cprintf("  edata  %08x (virt)  %08x (phys)\n", edata, (uint32_t)(edata - KERNBASE));
84         cprintf("  end    %08x (virt)  %08x (phys)\n", end, (uint32_t)(end - KERNBASE));
85         cprintf("Kernel executable memory footprint: %dKB\n",
86                 (uint32_t)(end-_start+1023)/1024);
87         return 0;
88 }
89
90 #if 0
91 zra: not called
92 static char RO* function_of(uint32_t address)
93 {
94         extern stab_t (RO stab)[], (RO estab)[];
95         extern char (RO stabstr)[];
96         stab_t* symtab;
97         stab_t* best_symtab = 0;
98         uint32_t best_func = 0;
99
100         // ugly and unsorted
101         for (symtab = stab; symtab < estab; symtab++) {
102                 // only consider functions, type = N_FUN
103                 if ((symtab->n_type == N_FUN) &&
104                     (symtab->n_value <= address) &&
105                         (symtab->n_value > best_func)) {
106                         best_func = symtab->n_value;
107                         best_symtab = symtab;
108                 }
109         }
110         // maybe the first stab really is the right one...  we'll see.
111         if (best_symtab == 0)
112                 return "Function not found!";
113         return stabstr + best_symtab->n_strx;
114 }
115 #endif
116
117 int mon_backtrace(int argc, char **argv, trapframe_t *tf)
118 {
119         backtrace();
120         return 0;
121 }
122
123 int mon_reboot(int argc, char **argv, trapframe_t *tf)
124 {
125         cprintf("[Scottish Accent]: She's goin' down, Cap'n!\n");
126         reboot();
127
128         // really, should never see this
129         cprintf("Sigh....\n");
130         return 0;
131 }
132
133 int mon_showmapping(int argc, char **argv, trapframe_t *tf)
134 {
135         if (argc < 2) {
136                 cprintf("Shows virtual -> physical mappings for a virtual address range.\n");
137                 cprintf("Usage: showmapping START_ADDR [END_ADDR]\n");
138                 return 1;
139         }
140         pde_t* pgdir = (pde_t*)vpd;
141         pte_t *pte, *pde;
142         page_t* page;
143         uintptr_t start, i;
144         size_t size;
145         start = ROUNDDOWN(strtol(argv[1], 0, 16), PGSIZE);
146         size = (argc == 2) ? 1 : strtol(argv[2], 0, 16) - start;
147         if (size/PGSIZE > 512) {
148                 cprintf("Not going to do this for more than 512 items\n");
149                 return 1;
150         }
151
152         show_mapping(start,size);
153         return 0;
154 }
155
156 int mon_setmapperm(int argc, char **argv, trapframe_t *tf)
157 {
158 #ifndef __i386__
159         cprintf("I don't support this call yet!\n");
160         return 1;
161 #else
162         if (argc < 3) {
163                 cprintf("Sets VIRT_ADDR's mapping's permissions to PERMS (in hex)\n");
164                 cprintf("Only affects the lowest level PTE.  To adjust the PDE, do the math.\n");
165                 cprintf("Be careful with this around UVPT, VPT, and friends.\n");
166                 cprintf("Usage: setmapperm VIRT_ADDR PERMS\n");
167                 return 1;
168         }
169         pde_t*COUNT(PTSIZE) pgdir = (pde_t*COUNT(PTSIZE))vpd;
170         pte_t *pte, *pde;
171         page_t* page;
172         uintptr_t va;
173         va = ROUNDDOWN(strtol(argv[1], 0, 16), PGSIZE);
174         page = page_lookup(pgdir, (void*SNT)va, &pte);
175         if (!page) {
176                 cprintf("No such mapping\n");
177                 return 1;
178         }
179         pde = &pgdir[PDX(va)];
180         cprintf("   Virtual    Physical  Ps Dr Ac CD WT U W\n");
181         cprintf("------------------------------------------\n");
182         cprintf("%08p  %08p  %1d  %1d  %1d  %1d  %1d  %1d %1d\n", va, page2pa(page),
183                (*pte & PTE_PS) >> 7, (*pte & PTE_D) >> 6, (*pte & PTE_A) >> 5,
184                (*pte & PTE_PCD) >> 4, (*pte & PTE_PWT) >> 3, (*pte & *pde & PTE_U) >> 2,
185                (*pte & *pde & PTE_W) >> 1);
186         *pte = PTE_ADDR(*pte) | (*pte & PTE_PS) |
187                (PGOFF(strtol(argv[2], 0, 16)) & ~PTE_PS ) | PTE_P;
188         cprintf("%08p  %08p  %1d  %1d  %1d  %1d  %1d  %1d %1d\n", va, page2pa(page),
189                (*pte & PTE_PS) >> 7, (*pte & PTE_D) >> 6, (*pte & PTE_A) >> 5,
190                (*pte & PTE_PCD) >> 4, (*pte & PTE_PWT) >> 3, (*pte & *pde & PTE_U) >> 2,
191                (*pte & *pde & PTE_W) >> 1);
192         return 0;
193 #endif
194 }
195
196 int mon_cpuinfo(int argc, char **argv, trapframe_t *tf)
197 {
198         cprintf("Number of CPUs detected: %d\n", num_cpus);
199         cprintf("Calling CPU's ID: 0x%08x\n", core_id());
200
201         if (argc < 2)
202                 smp_call_function_self(test_print_info_handler, NULL, 0);
203         else
204                 smp_call_function_single(strtol(argv[1], 0, 10),
205                                          test_print_info_handler, NULL, 0);
206         return 0;
207 }
208
209 int mon_manager(int argc, char** argv, trapframe_t *tf)
210 {
211         manager();
212         panic("should never get here");
213         return 0;
214 }
215
216 int mon_nanwan(int argc, char **argv, trapframe_t *tf)
217 {
218         /* Borrowed with love from http://www.geocities.com/SoHo/7373/zoo.htm
219          * (http://www.ascii-art.com/).  Slightly modified to make it 25 lines tall.
220          */
221         printk("\n");
222         printk("             .-.  .-.\n");
223         printk("             |  \\/  |\n");
224         printk("            /,   ,_  `'-.\n");
225         printk("          .-|\\   /`\\     '. \n");
226         printk("        .'  0/   | 0\\  \\_  `\".  \n");
227         printk("     .-'  _,/    '--'.'|#''---'\n");
228         printk("      `--'  |       /   \\#\n");
229         printk("            |      /     \\#\n");
230         printk("            \\     ;|\\    .\\#\n");
231         printk("            |' ' //  \\   ::\\# \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("                             jgs \\   ::\\#\n");
244         printk("                                  \\      \n");
245         return 0;
246 }
247
248 int mon_kfs_ls(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
249 {
250         printk("Files in KFS:\n-------------------------------\n");
251         for (int i = 0; i < MAX_KFS_FILES; i++)
252                 if (kfs[i].name[0])
253                         printk("%s\n", kfs[i].name);
254         return 0;
255 }
256
257 int mon_kfs_run(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
258 {
259         if (argc != 2) {
260                 printk("Usage: kfs_run FILENAME\n");
261                 return 1;
262         }
263         int kfs_inode = kfs_lookup_path(argv[1]);
264         if (kfs_inode < 0) {
265                 printk("Bad filename!\n");
266                 return 1;
267         }
268         struct proc *p = kfs_proc_create(kfs_inode);
269         // go from PROC_CREATED->PROC_RUNNABLE_S
270         spin_lock(&p->proc_lock); // might not be necessary for a mon function
271         __proc_set_state(p, PROC_RUNNABLE_S);
272         schedule_proc(p);
273         spin_unlock(&p->proc_lock);
274         proc_decref(p, 1); // let go of the reference created in proc_create()
275         // Should never return from schedule (env_pop in there)
276         // also note you may not get the process you created, in the event there
277         // are others floating around that are runnable
278         schedule();
279         return 0;
280 }
281
282 int mon_kfs_cat(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
283 {
284         if (argc != 2) {
285                 printk("Usage: kfs_cat FILENAME\n");
286                 return 1;
287         }
288         int kfs_inode = kfs_lookup_path(argv[1]);
289         if (kfs_inode < 0) {
290                 printk("Bad filename!\n");
291                 return 1;
292         }
293         kfs_cat(kfs_inode);
294         return 0;
295 }
296
297 int mon_procinfo(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
298 {
299         if (argc < 2) {
300                 printk("Usage: procinfo OPTION\n");
301                 printk("\tidlecores: show idle core map\n");
302                 printk("\tall: show all active pids\n");
303                 printk("\trunnable: show proc_runnablelist\n");
304                 printk("\tresources: show resources wanted/granted for all procs\n");
305                 printk("\tpid NUM: show a lot of info for proc NUM\n");
306                 printk("\tunlock NUM: unlock the lock for proc NUM (OMG!!!)\n");
307                 printk("\tkill NUM: destroy proc NUM\n");
308                 return 1;
309         }
310         if (!strcmp(argv[1], "idlecores")) {
311                 print_idlecoremap();
312         } else if (!strcmp(argv[1], "all")) {
313                 print_allpids();
314         } else if (!strcmp(argv[1], "runnable")) {
315                 dump_proclist(&proc_runnablelist);
316         } else if (!strcmp(argv[1], "resources")) {
317                 print_all_resources();
318         } else if (!strcmp(argv[1], "pid")) {
319                 if (argc != 3) {
320                         printk("Give me a pid number.\n");
321                         return 1;
322                 }
323                 print_proc_info(strtol(argv[2], 0, 0));
324         } else if (!strcmp(argv[1], "unlock")) {
325                 if (argc != 3) {
326                         printk("Give me a pid number.\n");
327                         return 1;
328                 }
329                 struct proc *p = pid2proc(strtol(argv[2], 0, 0));
330                 if (!p) {
331                         printk("No such proc\n");
332                         return 1;
333                 }
334                 spin_unlock(&p->proc_lock);
335                 proc_decref(p, 1);
336         } else if (!strcmp(argv[1], "kill")) {
337                 if (argc != 3) {
338                         printk("Give me a pid number.\n");
339                         return 1;
340                 }
341                 struct proc *p = pid2proc(strtol(argv[2], 0, 0));
342                 if (!p) {
343                         printk("No such proc\n");
344                         return 1;
345                 }
346                 proc_destroy(p);
347                 proc_decref(p, 1);
348         } else {
349                 printk("Bad option\n");
350                 return 1;
351         }
352         return 0;
353 }
354
355 int mon_exit(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
356 {
357         return -1;
358 }
359
360 int mon_kfunc(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
361 {
362         #ifndef __i386__
363         printk("Only supported on x86 for now.  =(\n");
364         return -1;
365         #endif
366
367         void (*func)(void *arg, ...);
368
369         if (argc < 2) {
370                 printk("Usage: kfunc FUNCTION [arg1] [arg2] [etc]\n");
371                 printk("Arguments must be in hex.  Can take 6 args.\n");
372                 return 1;
373         }
374         func = debug_get_fn_addr(argv[1]);
375         if (!func) {
376                 printk("Function not found.\n");
377                 return 1;
378         }
379         /* Not elegant, but whatever.  maybe there's a better syntax, or we can do
380          * it with asm magic. */
381         switch (argc) {
382                 case 2: /* have to fake one arg */
383                         func((void*)0);
384                         break;
385                 case 3: /* the real first arg */
386                         func((void*)strtol(argv[2], 0, 16));
387                         break;
388                 case 4:
389                         func((void*)strtol(argv[2], 0, 16),
390                                     strtol(argv[3], 0, 16));
391                         break;
392                 case 5:
393                         func((void*)strtol(argv[2], 0, 16),
394                                     strtol(argv[3], 0, 16),
395                                     strtol(argv[4], 0, 16));
396                         break;
397                 case 6:
398                         func((void*)strtol(argv[2], 0, 16),
399                                     strtol(argv[3], 0, 16),
400                                     strtol(argv[4], 0, 16),
401                                     strtol(argv[5], 0, 16));
402                         break;
403                 case 7:
404                         func((void*)strtol(argv[2], 0, 16),
405                                     strtol(argv[3], 0, 16),
406                                     strtol(argv[4], 0, 16),
407                                     strtol(argv[5], 0, 16),
408                                     strtol(argv[6], 0, 16));
409                         break;
410                 case 8:
411                         func((void*)strtol(argv[2], 0, 16),
412                                     strtol(argv[3], 0, 16),
413                                     strtol(argv[4], 0, 16),
414                                     strtol(argv[5], 0, 16),
415                                     strtol(argv[6], 0, 16),
416                                     strtol(argv[7], 0, 16));
417                         break;
418                 default:
419                         printk("Bad number of arguments.\n");
420                         return -1;
421         }
422         return 0;
423 }
424
425 int mon_notify(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
426 {
427         struct proc *p;
428         unsigned int num;
429         uint32_t vcoreid;
430
431         if (argc < 3) {
432                 printk("Usage: notify PID NUM [VCOREID]\n");
433                 return 1;
434         }
435         p = pid2proc(strtol(argv[1], 0, 0));
436         if (!p) {
437                 printk("No such proc\n");
438                 return 1;
439         }
440         num = strtol(argv[2], 0, 0);
441         if (argc == 4) {
442                 vcoreid = strtol(argv[3], 0, 0);
443                 do_notify(p, vcoreid, num, 0);
444         } else {
445                 proc_notify(p, num, 0);
446         }
447         proc_decref(p, 1);
448         return 0;
449 }
450 /***** Kernel monitor command interpreter *****/
451
452 #define WHITESPACE "\t\r\n "
453 #define MAXARGS 16
454
455 static int runcmd(char *NTS real_buf, trapframe_t *tf) {
456         char * buf = NTEXPAND(real_buf);
457         int argc;
458         char *NTS argv[MAXARGS];
459         int i;
460
461         // Parse the command buffer into whitespace-separated arguments
462         argc = 0;
463         argv[argc] = 0;
464         while (1) {
465                 // gobble whitespace
466                 while (*buf && strchr(WHITESPACE, *buf))
467                         *buf++ = 0;
468                 if (*buf == 0)
469                         break;
470
471                 // save and scan past next arg
472                 if (argc == MAXARGS-1) {
473                         cprintf("Too many arguments (max %d)\n", MAXARGS);
474                         return 0;
475                 }
476                 //This will get fucked at runtime..... in the ASS
477                 argv[argc++] = buf;
478                 while (*buf && !strchr(WHITESPACE, *buf))
479                         buf++;
480         }
481         argv[argc] = 0;
482
483         // Lookup and invoke the command
484         if (argc == 0)
485                 return 0;
486         for (i = 0; i < NCOMMANDS; i++) {
487                 if (strcmp(argv[0], commands[i].name) == 0)
488                         return commands[i].func(argc, argv, tf);
489         }
490         cprintf("Unknown command '%s'\n", argv[0]);
491         return 0;
492 }
493
494 void monitor(trapframe_t *tf) {
495         static spinlock_t monitor_lock = SPINLOCK_INITIALIZER;
496         spin_lock_irqsave(&monitor_lock);
497
498         char *buf;
499
500         printk("Welcome to the ROS kernel monitor on core %d!\n", core_id());
501         printk("Type 'help' for a list of commands.\n");
502
503         if (tf != NULL)
504                 print_trapframe(tf);
505
506         spin_unlock_irqsave(&monitor_lock);
507         while (1) {
508                 spin_lock_irqsave(&monitor_lock);
509                 buf = readline("K> ");
510                 if (buf != NULL) {
511                         spin_unlock_irqsave(&monitor_lock);
512                         if (runcmd(buf, tf) < 0)
513                                 break;
514                 }
515         }
516 }