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