Andrew's port to sparc
[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/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 <manager.h>
22
23 #include <ros/memlayout.h>
24
25 #define CMDBUF_SIZE     80      // enough for one VGA text line
26
27 typedef struct command {
28         const char *NTS name;
29         const char *NTS desc;
30         // return -1 to force monitor to exit
31         int (*func)(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf);
32 } command_t;
33
34 static command_t commands[] = {
35         { "help", "Display this list of commands", mon_help },
36         { "kerninfo", "Display information about the kernel", mon_kerninfo },
37         { "backtrace", "Dump a backtrace", mon_backtrace },
38         { "reboot", "Take a ride to the South Bay", mon_reboot },
39         { "showmapping", "Shows VA->PA mappings between two virtual addresses (parameters)", mon_showmapping},
40         { "setmapperm", "Sets permissions on a VA->PA mapping", mon_setmapperm},
41         { "cpuinfo", "Prints CPU diagnostics", mon_cpuinfo},
42         { "nanwan", "Meet Nanwan!!", mon_nanwan},
43         { "manager", "Run the manager", mon_manager},
44 };
45 #define NCOMMANDS (sizeof(commands)/sizeof(commands[0]))
46
47 /***** Implementations of basic kernel monitor commands *****/
48
49 int mon_help(int argc, char **argv, trapframe_t *tf)
50 {
51         int i;
52
53         for (i = 0; i < NCOMMANDS; i++)
54                 cprintf("%s - %s\n", commands[i].name, commands[i].desc);
55         return 0;
56 }
57
58 int mon_kerninfo(int argc, char **argv, trapframe_t *tf)
59 {
60         extern char (SNT _start)[], (SNT etext)[], (SNT edata)[], (SNT end)[];
61
62         cprintf("Special kernel symbols:\n");
63         cprintf("  _start %08x (virt)  %08x (phys)\n", _start, (uint32_t)(_start - KERNBASE));
64         cprintf("  etext  %08x (virt)  %08x (phys)\n", etext, (uint32_t)(etext - KERNBASE));
65         cprintf("  edata  %08x (virt)  %08x (phys)\n", edata, (uint32_t)(edata - KERNBASE));
66         cprintf("  end    %08x (virt)  %08x (phys)\n", end, (uint32_t)(end - KERNBASE));
67         cprintf("Kernel executable memory footprint: %dKB\n",
68                 (uint32_t)(end-_start+1023)/1024);
69         return 0;
70 }
71
72 static char* function_of(uint32_t address) 
73 {
74         extern stab_t stab[], estab[];
75         extern char stabstr[];
76         stab_t* symtab;
77         stab_t* best_symtab = 0;
78         uint32_t best_func = 0;
79         
80         // ugly and unsorted
81         for (symtab = stab; symtab < estab; symtab++) {
82                 // only consider functions, type = N_FUN
83                 if ((symtab->n_type == N_FUN) && 
84                     (symtab->n_value <= address) && 
85                         (symtab->n_value > best_func)) {
86                         best_func = symtab->n_value;
87                         best_symtab = symtab;
88                 }
89         }
90         // maybe the first stab really is the right one...  we'll see.
91         if (best_symtab == 0)
92                 return "Function not found!";
93         return stabstr + best_symtab->n_strx;
94 }
95
96 int mon_backtrace(int argc, char **argv, trapframe_t *tf)
97 {
98         backtrace();
99         return 0;
100 }
101
102 int mon_reboot(int argc, char **argv, trapframe_t *tf)
103 {
104         cprintf("[Irish Accent]: She's goin' down, Cap'n!\n");
105         reboot();
106
107         // really, should never see this
108         cprintf("Sigh....\n");
109         return 0;
110 }
111
112 int mon_showmapping(int argc, char **argv, trapframe_t *tf)
113 {
114         if (argc < 2) {
115                 cprintf("Shows virtual -> physical mappings for a virtual address range.\n");
116                 cprintf("Usage: showmappings START_ADDR [END_ADDR]\n");
117                 return 1;
118         }
119         pde_t* pgdir = (pde_t*)vpd;
120         pte_t *pte, *pde;
121         page_t* page;
122         uintptr_t start, i;
123         size_t size;
124         start = ROUNDDOWN(strtol(argv[1], 0, 16), PGSIZE);
125         size = (argc == 2) ? 1 : strtol(argv[2], 0, 16) - start;
126         if (size/PGSIZE > 512) {
127                 cprintf("Not going to do this for more than 512 items\n");
128                 return 1;
129         }
130
131         show_mapping(start,size);
132         return 0;
133 }
134
135 int mon_setmapperm(int argc, char **argv, trapframe_t *tf)
136 {
137 #ifndef __i386__
138         cprintf("I don't support this call yet!\n");
139         return 1;
140 #else
141         if (argc < 3) {
142                 cprintf("Sets VIRT_ADDR's mapping's permissions to PERMS (in hex)\n");
143                 cprintf("Only affects the lowest level PTE.  To adjust the PDE, do the math.\n");
144                 cprintf("Be careful with this around UVPT, VPT, and friends.\n");
145                 cprintf("Usage: setmapperm VIRT_ADDR PERMS\n");
146                 return 1;
147         }
148         pde_t* pgdir = (pde_t*)vpd;
149         pte_t *pte, *pde;
150         page_t* page;
151         uintptr_t va;
152         va = ROUNDDOWN(strtol(argv[1], 0, 16), PGSIZE);
153         page = page_lookup(pgdir, (void*)va, &pte);
154         if (!page) {
155                 cprintf("No such mapping\n");
156                 return 1;
157         }
158         pde = &pgdir[PDX(va)];
159         cprintf("   Virtual    Physical  Ps Dr Ac CD WT U W\n");
160         cprintf("------------------------------------------\n");
161         cprintf("%08p  %08p  %1d  %1d  %1d  %1d  %1d  %1d %1d\n", va, page2pa(page), 
162                (*pte & PTE_PS) >> 7, (*pte & PTE_D) >> 6, (*pte & PTE_A) >> 5, 
163                (*pte & PTE_PCD) >> 4, (*pte & PTE_PWT) >> 3, (*pte & *pde & PTE_U) >> 2, 
164                (*pte & *pde & PTE_W) >> 1);
165         *pte = PTE_ADDR(*pte) | (*pte & PTE_PS) |
166                (PGOFF(strtol(argv[2], 0, 16)) & ~PTE_PS ) | PTE_P;
167         cprintf("%08p  %08p  %1d  %1d  %1d  %1d  %1d  %1d %1d\n", va, page2pa(page), 
168                (*pte & PTE_PS) >> 7, (*pte & PTE_D) >> 6, (*pte & PTE_A) >> 5, 
169                (*pte & PTE_PCD) >> 4, (*pte & PTE_PWT) >> 3, (*pte & *pde & PTE_U) >> 2, 
170                (*pte & *pde & PTE_W) >> 1);
171         return 0;
172 #endif
173 }
174
175 int mon_cpuinfo(int argc, char **argv, trapframe_t *tf)
176 {
177         extern uint8_t num_cpus;
178
179         cprintf("Number of CPUs detected: %d\n", num_cpus);     
180         cprintf("Calling CPU's ID: 0x%08x\n", core_id());
181
182 #ifdef __i386__
183         if (argc < 2)
184                 smp_call_function_self(test_print_info_handler, 0, 0);
185         else
186                 smp_call_function_single(strtol(argv[1], 0, 16),
187                                          test_print_info_handler, 0, 0);
188 #endif
189         return 0;
190 }
191
192 int mon_manager(int argc, char** argv, trapframe_t *tf)
193 {
194         manager();
195         panic("should never get here");
196         return 0;
197 }
198
199 int mon_nanwan(int argc, char **argv, trapframe_t *tf)
200 {
201         /* Borrowed with love from http://www.geocities.com/SoHo/7373/zoo.htm
202          * (http://www.ascii-art.com/).  Slightly modified to make it 25 lines tall.
203          */
204         printk("\n");
205         printk("             .-.  .-.\n");
206         printk("             |  \\/  |\n");
207         printk("            /,   ,_  `'-.\n");
208         printk("          .-|\\   /`\\     '. \n");
209         printk("        .'  0/   | 0\\  \\_  `\".  \n");
210         printk("     .-'  _,/    '--'.'|#''---'\n");
211         printk("      `--'  |       /   \\#\n");
212         printk("            |      /     \\#\n");
213         printk("            \\     ;|\\    .\\#\n");
214         printk("            |' ' //  \\   ::\\# \n");
215         printk("            \\   /`    \\   ':\\#\n");
216         printk("             `\"`       \\..   \\#\n");
217         printk("                        \\::.  \\#\n");
218         printk("                         \\::   \\#\n");
219         printk("                          \\'  .:\\#\n");
220         printk("                           \\  :::\\#\n");
221         printk("                            \\  '::\\#\n");
222         printk("                             \\     \\#\n");
223         printk("                              \\:.   \\#\n");
224         printk("                               \\::   \\#\n");
225         printk("                                \\'   .\\#\n");
226         printk("                             jgs \\   ::\\#\n");
227         printk("                                  \\      \n");
228         return 0;
229 }
230
231 /***** Kernel monitor command interpreter *****/
232
233 #define WHITESPACE "\t\r\n "
234 #define MAXARGS 16
235
236 static int runcmd(char *COUNT(CMDBUF_SIZE) real_buf, trapframe_t *tf) {
237         char *BND(real_buf, real_buf+CMDBUF_SIZE) buf = real_buf;
238         int argc;
239         char *NTS argv[MAXARGS];
240         int i;
241
242         // Parse the command buffer into whitespace-separated arguments
243         argc = 0;
244         argv[argc] = 0;
245         while (1) {
246                 // gobble whitespace
247                 while (*buf && strchr(WHITESPACE, *buf))
248                         *buf++ = 0;
249                 if (*buf == 0)
250                         break;
251
252                 // save and scan past next arg
253                 if (argc == MAXARGS-1) {
254                         cprintf("Too many arguments (max %d)\n", MAXARGS);
255                         return 0;
256                 }
257                 //This will get fucked at runtime..... in the ASS
258                 argv[argc++] = (char *NTS) TC(buf);
259                 while (*buf && !strchr(WHITESPACE, *buf))
260                         buf++;
261         }
262         argv[argc] = 0;
263
264         // Lookup and invoke the command
265         if (argc == 0)
266                 return 0;
267         for (i = 0; i < NCOMMANDS; i++) {
268                 if (strcmp(argv[0], commands[i].name) == 0)
269                         return commands[i].func(argc, argv, tf);
270         }
271         cprintf("Unknown command '%s'\n", argv[0]);
272         return 0;
273 }
274
275 void monitor(trapframe_t *tf) {
276         char *buf;
277
278         cprintf("Welcome to the ROS kernel monitor!\n");
279         cprintf("Type 'help' for a list of commands.\n");
280
281         if (tf != NULL)
282                 print_trapframe(tf);
283
284         while (1) {
285                 buf = readline("K> ");
286                 if (buf != NULL)
287                         if (runcmd(buf, tf) < 0)
288                                 break;
289         }
290 }