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