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