Process state work, initial steps
[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 __DEPUTY__
5 #pragma nodeputy
6 #endif
7
8 #include <arch/x86.h>
9 #include <arch/stab.h>
10 #include <arch/apic.h>
11 #include <arch/smp.h>
12 #include <arch/console.h>
13
14 #include <stdio.h>
15 #include <string.h>
16 #include <assert.h>
17 #include <monitor.h>
18 #include <trap.h>
19 #include <pmap.h>
20 #include <kdebug.h>
21 #include <testing.h>
22 #include <kfs.h>
23
24 #include <ros/memlayout.h>
25
26 #define CMDBUF_SIZE     80      // enough for one VGA text line
27
28 typedef struct command {
29         const char *NTS name;
30         const char *NTS desc;
31         // return -1 to force monitor to exit
32         int (*func)(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf);
33 } command_t;
34
35 static command_t commands[] = {
36         { "help", "Display this list of commands", mon_help },
37         { "kerninfo", "Display information about the kernel", mon_kerninfo },
38         { "backtrace", "Dump a backtrace", mon_backtrace },
39         { "reboot", "Take a ride to the South Bay", mon_reboot },
40         { "showmapping", "Shows VA->PA mappings between two virtual addresses (parameters)", mon_showmapping},
41         { "setmapperm", "Sets permissions on a VA->PA mapping", mon_setmapperm},
42         { "cpuinfo", "Prints CPU diagnostics", mon_cpuinfo},
43         { "nanwan", "Meet Nanwan!!", mon_nanwan},
44         { "kfs_ls", "List files in KFS", mon_kfs_ls},
45         { "kfs_run", "Create and run a program from KFS", mon_kfs_run},
46 };
47 #define NCOMMANDS (sizeof(commands)/sizeof(commands[0]))
48
49 /***** Implementations of basic kernel monitor commands *****/
50
51 int mon_help(int argc, char **argv, trapframe_t *tf)
52 {
53         int i;
54
55         for (i = 0; i < NCOMMANDS; i++)
56                 cprintf("%s - %s\n", commands[i].name, commands[i].desc);
57         return 0;
58 }
59
60 int mon_kerninfo(int argc, char **argv, trapframe_t *tf)
61 {
62         extern char (SNT _start)[], (SNT etext)[], (SNT edata)[], (SNT end)[];
63
64         cprintf("Special kernel symbols:\n");
65         cprintf("  _start %08x (virt)  %08x (phys)\n", _start, (uint32_t)(_start - KERNBASE));
66         cprintf("  etext  %08x (virt)  %08x (phys)\n", etext, (uint32_t)(etext - KERNBASE));
67         cprintf("  edata  %08x (virt)  %08x (phys)\n", edata, (uint32_t)(edata - KERNBASE));
68         cprintf("  end    %08x (virt)  %08x (phys)\n", end, (uint32_t)(end - KERNBASE));
69         cprintf("Kernel executable memory footprint: %dKB\n",
70                 (uint32_t)(end-_start+1023)/1024);
71         return 0;
72 }
73
74 static char* function_of(uint32_t address) 
75 {
76         extern stab_t stab[], estab[];
77         extern char stabstr[];
78         stab_t* symtab;
79         stab_t* best_symtab = 0;
80         uint32_t best_func = 0;
81         
82         // ugly and unsorted
83         for (symtab = stab; symtab < estab; symtab++) {
84                 // only consider functions, type = N_FUN
85                 if ((symtab->n_type == N_FUN) && 
86                     (symtab->n_value <= address) && 
87                         (symtab->n_value > best_func)) {
88                         best_func = symtab->n_value;
89                         best_symtab = symtab;
90                 }
91         }
92         // maybe the first stab really is the right one...  we'll see.
93         if (best_symtab == 0)
94                 return "Function not found!";
95         return stabstr + best_symtab->n_strx;
96 }
97
98 int mon_backtrace(int argc, char **argv, trapframe_t *tf)
99 {
100         uint32_t* ebp, eip;
101         eipdebuginfo_t debuginfo;
102         char buf[256];
103         int j, i = 1;
104         ebp = (uint32_t*)read_ebp();    
105         // this is part of the way back into the call() instruction's bytes
106         // eagle-eyed readers should be able to explain why this is good enough,
107         // and retaddr (just *(ebp + 1) is not)
108         eip = *(ebp + 1) - 1;
109         // jump back a frame (out of mon_backtrace)
110         ebp = (uint32_t*)(*ebp);
111         cprintf("Stack Backtrace:\n");
112         // on each iteration, ebp holds the stack frame and eip an addr in that func
113         while (ebp != 0) {
114                 debuginfo_eip(eip, &debuginfo);
115                 memset(buf, 0, 256);
116                 strncpy(buf, debuginfo.eip_fn_name, MIN(debuginfo.eip_fn_namelen, 256));
117                 buf[MIN(debuginfo.eip_fn_namelen, 255)] = 0;
118                 cprintf("#%02d [<%x>] in %s+%x(%p) from %s:%d\n", i++,  eip, buf, 
119                         debuginfo.eip_fn_addr - (uint32_t)_start, debuginfo.eip_fn_addr, 
120                         debuginfo.eip_file, debuginfo.eip_line);
121                 cprintf("    ebp: %x   Args:", ebp);
122                 for (j = 0; j < MIN(debuginfo.eip_fn_narg, 5); j++)
123                         cprintf(" %08x", *(ebp + 2 + j));
124                 cprintf("\n");
125                 eip = *(ebp + 1) - 1;
126                 ebp = (uint32_t*)(*ebp);
127         }
128         return 0;
129 }
130
131 int mon_reboot(int argc, char **argv, trapframe_t *tf)
132 {
133         cprintf("[Irish Accent]: She's goin' down, Cap'n!\n");
134         outb(0x92, 0x3);
135         // KVM doesn't reboot yet, but this next bit will make it
136         // if you're in kernel mode and you can't do a push, when an interrupt
137         // comes in, the system just resets.  if esp = 0, there's no room left.
138         // somewhat curious about what happens in an SMP....
139         cprintf("[Irish Accent]: I'm givin' you all she's got!\n");
140         asm volatile ("movl $0, %esp; int $0");
141         // really, should never see this
142         cprintf("Sigh....\n");
143         return 0;
144 }
145
146 int mon_showmapping(int argc, char **argv, trapframe_t *tf)
147 {
148         if (argc < 2) {
149                 cprintf("Shows virtual -> physical mappings for a virtual address range.\n");
150                 cprintf("Usage: showmappings START_ADDR [END_ADDR]\n");
151                 return 1;
152         }
153         pde_t* pgdir = (pde_t*)vpd;
154         pte_t *pte, *pde;
155         page_t* page;
156         uintptr_t start, i;
157         size_t size;
158         start = ROUNDDOWN(strtol(argv[1], 0, 16), PGSIZE);
159         size = (argc == 2) ? 1 : strtol(argv[2], 0, 16) - start;
160         if (size/PGSIZE > 512) {
161                 cprintf("Not going to do this for more than 512 items\n");
162                 return 1;
163         }
164         cprintf("   Virtual    Physical  Ps Dr Ac CD WT U W\n");
165         cprintf("------------------------------------------\n");
166         for(i = 0; i < size; i += PGSIZE, start += PGSIZE) {
167                 page = page_lookup(pgdir, (void*)start, &pte);
168                 cprintf("%08p  ", start);
169                 if (page) {
170                         pde = &pgdir[PDX(start)];
171                         // for a jumbo, pde = pte and PTE_PS (better be) = 1
172                         cprintf("%08p  %1d  %1d  %1d  %1d  %1d  %1d %1d\n", page2pa(page), 
173                                (*pte & PTE_PS) >> 7, (*pte & PTE_D) >> 6, (*pte & PTE_A) >> 5,
174                                (*pte & PTE_PCD) >> 4, (*pte & PTE_PWT) >> 3, 
175                                (*pte & *pde & PTE_U) >> 2, (*pte & *pde & PTE_W) >> 1);
176                 } else
177                         cprintf("%08p\n", 0);
178         }
179         return 0;
180 }
181
182 int mon_setmapperm(int argc, char **argv, trapframe_t *tf)
183 {
184         if (argc < 3) {
185                 cprintf("Sets VIRT_ADDR's mapping's permissions to PERMS (in hex)\n");
186                 cprintf("Only affects the lowest level PTE.  To adjust the PDE, do the math.\n");
187                 cprintf("Be careful with this around UVPT, VPT, and friends.\n");
188                 cprintf("Usage: setmapperm VIRT_ADDR PERMS\n");
189                 return 1;
190         }
191         pde_t* pgdir = (pde_t*)vpd;
192         pte_t *pte, *pde;
193         page_t* page;
194         uintptr_t va;
195         va = ROUNDDOWN(strtol(argv[1], 0, 16), PGSIZE);
196         page = page_lookup(pgdir, (void*)va, &pte);
197         if (!page) {
198                 cprintf("No such mapping\n");
199                 return 1;
200         }
201         pde = &pgdir[PDX(va)];
202         cprintf("   Virtual    Physical  Ps Dr Ac CD WT U W\n");
203         cprintf("------------------------------------------\n");
204         cprintf("%08p  %08p  %1d  %1d  %1d  %1d  %1d  %1d %1d\n", va, page2pa(page), 
205                (*pte & PTE_PS) >> 7, (*pte & PTE_D) >> 6, (*pte & PTE_A) >> 5, 
206                (*pte & PTE_PCD) >> 4, (*pte & PTE_PWT) >> 3, (*pte & *pde & PTE_U) >> 2, 
207                (*pte & *pde & PTE_W) >> 1);
208         *pte = PTE_ADDR(*pte) | (*pte & PTE_PS) |
209                (PGOFF(strtol(argv[2], 0, 16)) & ~PTE_PS ) | PTE_P;
210         cprintf("%08p  %08p  %1d  %1d  %1d  %1d  %1d  %1d %1d\n", va, page2pa(page), 
211                (*pte & PTE_PS) >> 7, (*pte & PTE_D) >> 6, (*pte & PTE_A) >> 5, 
212                (*pte & PTE_PCD) >> 4, (*pte & PTE_PWT) >> 3, (*pte & *pde & PTE_U) >> 2, 
213                (*pte & *pde & PTE_W) >> 1);
214         return 0;
215 }
216
217 int mon_cpuinfo(int argc, char **argv, trapframe_t *tf)
218 {
219         extern uint8_t num_cpus;
220
221         cprintf("Number of CPUs detected: %d\n", num_cpus);     
222         cprintf("Calling CPU's LAPIC ID: 0x%08x\n", lapic_get_id());
223         if (argc < 2)
224                 smp_call_function_self(test_print_info_handler, 0, 0);
225         else
226                 smp_call_function_single(strtol(argv[1], 0, 16),
227                                          test_print_info_handler, 0, 0);
228         return 0;
229 }
230
231 int mon_nanwan(int argc, char **argv, trapframe_t *tf)
232 {
233         /* Borrowed with love from http://www.geocities.com/SoHo/7373/zoo.htm
234          * (http://www.ascii-art.com/).  Slightly modified to make it 25 lines tall.
235          */
236         printk("\n");
237         printk("             .-.  .-.\n");
238         printk("             |  \\/  |\n");
239         printk("            /,   ,_  `'-.\n");
240         printk("          .-|\\   /`\\     '. \n");
241         printk("        .'  0/   | 0\\  \\_  `\".  \n");
242         printk("     .-'  _,/    '--'.'|#''---'\n");
243         printk("      `--'  |       /   \\#\n");
244         printk("            |      /     \\#\n");
245         printk("            \\     ;|\\    .\\#\n");
246         printk("            |' ' //  \\   ::\\# \n");
247         printk("            \\   /`    \\   ':\\#\n");
248         printk("             `\"`       \\..   \\#\n");
249         printk("                        \\::.  \\#\n");
250         printk("                         \\::   \\#\n");
251         printk("                          \\'  .:\\#\n");
252         printk("                           \\  :::\\#\n");
253         printk("                            \\  '::\\#\n");
254         printk("                             \\     \\#\n");
255         printk("                              \\:.   \\#\n");
256         printk("                               \\::   \\#\n");
257         printk("                                \\'   .\\#\n");
258         printk("                             jgs \\   ::\\#\n");
259         printk("                                  \\      \n");
260         return 0;
261 }
262
263 int mon_kfs_ls(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
264 {
265         printk("Files in KFS:\n-------------------------------\n");
266         for (int i = 0; i < MAX_KFS_FILES; i++)
267                 if (kfs[i].name[0])
268                         printk("%s\n", kfs[i].name);
269         return 0;
270 }
271
272 int mon_kfs_run(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
273 {
274         if (argc != 2) {
275                 printk("Usage: kfs_run FILENAME\n");
276                 return 1;
277         }
278         int kfs_inode = kfs_lookup_path(argv[1]);
279         if (kfs_inode < 0) {
280                 printk("Bad filename!\n");
281                 return 1;
282         }
283         struct proc *p = kfs_proc_create(kfs_inode);
284         // go from PROC_CREATED->PROC_RUNNABLE_S
285         proc_set_state(p, PROC_RUNNABLE_S);
286         // Should never return from schedule (env_pop in there)
287         // also note you may not get the process you created, in the event there
288         // are others floating around that are runnable
289         schedule();
290         return 0;
291 }
292
293 /***** Kernel monitor command interpreter *****/
294
295 #define WHITESPACE "\t\r\n "
296 #define MAXARGS 16
297
298 static int runcmd(char *COUNT(CMDBUF_SIZE) real_buf, trapframe_t *tf) {
299         char *BND(real_buf, real_buf+CMDBUF_SIZE) buf = real_buf;
300         int argc;
301         char *NTS argv[MAXARGS];
302         int i;
303
304         // Parse the command buffer into whitespace-separated arguments
305         argc = 0;
306         argv[argc] = 0;
307         while (1) {
308                 // gobble whitespace
309                 while (*buf && strchr(WHITESPACE, *buf))
310                         *buf++ = 0;
311                 if (*buf == 0)
312                         break;
313
314                 // save and scan past next arg
315                 if (argc == MAXARGS-1) {
316                         cprintf("Too many arguments (max %d)\n", MAXARGS);
317                         return 0;
318                 }
319                 //This will get fucked at runtime..... in the ASS
320                 argv[argc++] = (char *NTS) TC(buf);
321                 while (*buf && !strchr(WHITESPACE, *buf))
322                         buf++;
323         }
324         argv[argc] = 0;
325
326         // Lookup and invoke the command
327         if (argc == 0)
328                 return 0;
329         for (i = 0; i < NCOMMANDS; i++) {
330                 if (strcmp(argv[0], commands[i].name) == 0)
331                         return commands[i].func(argc, argv, tf);
332         }
333         cprintf("Unknown command '%s'\n", argv[0]);
334         return 0;
335 }
336
337 void monitor(trapframe_t *tf) {
338         char *buf;
339
340         cprintf("Welcome to the ROS kernel monitor!\n");
341         cprintf("Type 'help' for a list of commands.\n");
342
343         if (tf != NULL)
344                 print_trapframe(tf);
345
346         while (1) {
347                 buf = readline("K> ");
348                 if (buf != NULL)
349                         if (runcmd(buf, tf) < 0)
350                                 break;
351         }
352 }