Lab2, exercise 4 - basic VM init, paging
[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/kdebug.h>
14
15 #define CMDBUF_SIZE     80      // enough for one VGA text line
16
17 typedef struct command {
18         const char *NTS name;
19         const char *NTS desc;
20         // return -1 to force monitor to exit
21         int (*func)(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t* tf);
22 } command_t;
23
24 static command_t commands[] = {
25         { "help", "Display this list of commands", mon_help },
26         { "kerninfo", "Display information about the kernel", mon_kerninfo },
27         { "backtrace", "Dump a backtrace", mon_backtrace },
28         { "reboot", "Take a ride to the South Bay", mon_reboot },
29 };
30 #define NCOMMANDS (sizeof(commands)/sizeof(commands[0]))
31
32 /***** Implementations of basic kernel monitor commands *****/
33
34 int mon_help(int argc, char **argv, trapframe_t *tf)
35 {
36         int i;
37
38         for (i = 0; i < NCOMMANDS; i++)
39                 cprintf("%s - %s\n", commands[i].name, commands[i].desc);
40         return 0;
41 }
42
43 int mon_kerninfo(int argc, char **argv, trapframe_t *tf)
44 {
45         extern char (SNT _start)[], (SNT etext)[], (SNT edata)[], (SNT end)[];
46
47         cprintf("Special kernel symbols:\n");
48         cprintf("  _start %08x (virt)  %08x (phys)\n", _start, (uint32_t)(_start - KERNBASE));
49         cprintf("  etext  %08x (virt)  %08x (phys)\n", etext, (uint32_t)(etext - KERNBASE));
50         cprintf("  edata  %08x (virt)  %08x (phys)\n", edata, (uint32_t)(edata - KERNBASE));
51         cprintf("  end    %08x (virt)  %08x (phys)\n", end, (uint32_t)(end - KERNBASE));
52         cprintf("Kernel executable memory footprint: %dKB\n",
53                 (uint32_t)(end-_start+1023)/1024);
54         return 0;
55 }
56
57 static char* function_of(uint32_t address) 
58 {
59         extern stab_t stab[], estab[];
60         extern char stabstr[];
61         stab_t* symtab;
62         stab_t* best_symtab = 0;
63         uint32_t best_func = 0;
64         
65         // ugly and unsorted
66         for (symtab = stab; symtab < estab; symtab++) {
67                 // only consider functions, type = N_FUN
68                 if ((symtab->n_type == N_FUN) && 
69                     (symtab->n_value <= address) && 
70                         (symtab->n_value > best_func)) {
71                         best_func = symtab->n_value;
72                         best_symtab = symtab;
73                 }
74         }
75         // maybe the first stab really is the right one...  we'll see.
76         if (best_symtab == 0)
77                 return "Function not found!";
78         return stabstr + best_symtab->n_strx;
79 }
80
81 int mon_backtrace(int argc, char **argv, trapframe_t *tf)
82 {
83         uint32_t* ebp, eip;
84         int i = 1;
85         ebp = (uint32_t*)read_ebp();    
86         // this is the retaddr for what called backtrace
87         eip = *(ebp + 1);
88         // jump back a frame (out of mon_backtrace)
89         ebp = (uint32_t*)(*ebp);
90         cprintf("Stack Backtrace:\n");
91         // on each iteration, ebp holds the stack frame and eip is a retaddr in that func
92         while (ebp != 0) {
93                 cprintf("%02d EBP: %x EIP: %x Function: %s\n   Args: %08x %08x %08x %08x %08x\n",
94                                 i++,
95                         ebp,
96                                 eip,
97                                 function_of(eip),
98                                 *(ebp + 2),
99                                 *(ebp + 3),
100                                 *(ebp + 4),
101                                 *(ebp + 5),
102                                 *(ebp + 6)
103                                 );
104                 eip = *(ebp + 1);
105                 ebp = (uint32_t*)(*ebp);
106         }
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         outb(0x92, 0x3);
114         cprintf("Should have rebooted.  Doesn't work yet in KVM...\n");
115         return 0;
116 }
117
118
119 /***** Kernel monitor command interpreter *****/
120
121 #define WHITESPACE "\t\r\n "
122 #define MAXARGS 16
123
124 static int runcmd(char *COUNT(CMDBUF_SIZE) real_buf, trapframe_t* tf) {
125         char *BND(real_buf, real_buf+CMDBUF_SIZE) buf = real_buf;
126         int argc;
127         char *NTS argv[MAXARGS];
128         int i;
129
130         // Parse the command buffer into whitespace-separated arguments
131         argc = 0;
132         argv[argc] = 0;
133         while (1) {
134                 // gobble whitespace
135                 while (*buf && strchr(WHITESPACE, *buf))
136                         *buf++ = 0;
137                 if (*buf == 0)
138                         break;
139
140                 // save and scan past next arg
141                 if (argc == MAXARGS-1) {
142                         cprintf("Too many arguments (max %d)\n", MAXARGS);
143                         return 0;
144                 }
145                 //This will get fucked at runtime..... in the ASS
146                 argv[argc++] = (char *NTS) TC(buf);
147                 while (*buf && !strchr(WHITESPACE, *buf))
148                         buf++;
149         }
150         argv[argc] = 0;
151
152         // Lookup and invoke the command
153         if (argc == 0)
154                 return 0;
155         for (i = 0; i < NCOMMANDS; i++) {
156                 if (strcmp(argv[0], commands[i].name) == 0)
157                         return commands[i].func(argc, argv, tf);
158         }
159         cprintf("Unknown command '%s'\n", argv[0]);
160         return 0;
161 }
162
163 void monitor(trapframe_t* tf) {
164         char *buf;
165
166         cprintf("Welcome to the ROS kernel monitor!\n");
167         cprintf("Type 'help' for a list of commands.\n");
168
169         while (1) {
170                 buf = readline("K> ");
171                 if (buf != NULL)
172                         if (runcmd(buf, tf) < 0)
173                                 break;
174         }
175 }