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