1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
|
#include "main/apic.h"
#include "main/io.h"
#include "util/printf.h"
#include "util/string.h"
/*
* Debug message behavior.
*
* To disable a dbg mode add ',-name' to this variable. To enable one add
* ',name'. For example to have everything except 'mm' and 'pagealloc' you would
* set DBG to 'all,-mm,-pagealloc'. To have only 'test', 'testpass', 'testfail'
* you would set DBG to '-all,test,testpass,testfail'.
*
* We generally recommend that you leave this set to 'all' with some of the
* less useful message types disabled. To see all available message types, and
* to potentially add to them see 'kernel/include/util/debug.h'
*
* Note that due to the way this is interpreted either 'all' or '-all' should
* always be the first thing in this variable. Note that this setting can be
* changed at runtime by modifying the dbg_modes global variable.
*/
#define INIT_DBG_MODES "-all,exec,elf,vm,syscall,print"
/* Below is a truly terrible poll-driven serial driver that we use for debugging
* purposes - it outputs to COM1, but
* this can be easily changed. It does not use interrupts, and cannot read input
* */
/* This port is COM1 */
#define PORT 0x3f8
/* Corresponding interrupt vector */
#define PORT_INTR 0x0d
uint64_t dbg_modes;
typedef struct dbg_mode
{
const char *d_name;
uint64_t d_mode;
const char *d_color;
} dbg_mode_t;
void dbg_init()
{
outb(PORT + 3, 0x80); /* Enable DLAB (set baud rate divisor) */
outb(PORT + 0, 0x03); /* Set divisor to 3 (lo byte) 38400 baud */
outb(PORT + 1, 0x00); /* (hi byte) */
outb(PORT + 3, 0x03); /* 8 bits, no parity, one stop bit */
outb(PORT + 2, 0xC7); /* Enable FIFO, clear them, with 14-byte threshold */
dbg_add_modes(INIT_DBG_MODES);
}
static dbg_mode_t dbg_tab[] = {DBG_TAB};
const char *dbg_color(uint64_t d_mode)
{
dbg_mode_t *mode;
for (mode = dbg_tab; mode->d_mode != 0UL; mode++)
{
if (mode->d_mode & d_mode)
{
return mode->d_color;
}
}
/* If we get here, something went seriously wrong */
panic("Unknown debug mode 0x%lx\n", d_mode);
}
static void dbg_puts(char *c)
{
while (*c != '\0')
{
/* Wait until the port is free */
while (!(inb(PORT + 5) & 0x20))
;
outb(PORT, (uint8_t)*c++);
}
}
#define BUFFER_SIZE 1024
void dbg_print(char *fmt, ...)
{
va_list args;
char buf[BUFFER_SIZE];
size_t count;
va_start(args, fmt);
count = (size_t)vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
if (count >= sizeof(buf))
{
dbg_puts(
"WARNING: The following message has been truncated due to "
"buffer size limitations.\n");
}
dbg_puts(buf);
}
void dbg_printinfo(dbg_infofunc_t func, const void *data)
{
char buf[BUFFER_SIZE];
func(data, buf, BUFFER_SIZE);
dbg_puts(buf);
}
#ifndef NDEBUG
/**
* searches for <code>name</code> in the list of known
* debugging modes specified above and, if it
* finds <code>name</code>, adds the corresponding
* debugging mode to a list
*/
void dbg_add_mode(const char *name)
{
long cancel;
dbg_mode_t *mode;
if (*name == '-')
{
cancel = 1;
name++;
}
else
{
cancel = 0;
}
for (mode = dbg_tab; mode->d_name != NULL; mode++)
{
if (strcmp(name, mode->d_name) == 0)
{
break;
}
}
if (mode->d_name == NULL)
{
dbg_print("Warning: Unknown debug option: \"%s\"\n", name);
return;
}
if (cancel)
{
dbg_modes &= ~mode->d_mode;
}
else
{
dbg_modes |= mode->d_mode;
}
}
/**
* Cycles through each comma-delimited debugging option and
* adds it to the debugging modes by calling dbg_add_mode
*/
void dbg_add_modes(const char *modes)
{
char env[256];
char *name;
strncpy(env, modes, sizeof(env));
/* Maybe it would be good if we did this without strtok, but I'm too lazy */
for (name = strtok(env, ","); name; name = strtok(NULL, ","))
{
dbg_add_mode(name);
}
}
size_t dbg_modes_info(const void *data, char *buf, size_t size)
{
KASSERT(NULL == data);
KASSERT(0 < size);
size_t osize = size;
dbg_mode_t *mode;
for (mode = dbg_tab; mode->d_name != NULL; ++mode)
{
if (dbg_modes & mode->d_mode && mode->d_mode != DBG_ALL)
{
int len;
if ((len = snprintf(buf, size, "%s,", mode->d_name)) >= (int)size)
{
break;
}
else
{
buf += len;
size -= len;
}
}
}
if (size == osize)
{
buf[0] = '\0';
return 0;
}
else
{
/* remove trailing comma */
buf[-1] = '\0';
return osize - size + 1;
}
}
#endif
/* This is meant as a good point to automatically set a breakpoint which will
* stop just after a panic has occured and printed its message. */
noreturn static void dbg_panic_halt()
{
__asm__ volatile("cli; hlt");
__builtin_unreachable();
}
#define PANIC_BUFSIZE 2048
noreturn void dbg_panic(const char *file, int line, const char *func,
const char *fmt, ...)
{
char buf[PANIC_BUFSIZE];
va_list args;
va_start(args, fmt);
DEBUG_ENTER
dbg_print("C%ld P%ld panic in %s:%u %s(): ", curcore.kc_id,
curproc ? curproc->p_pid : -1L, file, line, func);
vsnprintf(buf, PANIC_BUFSIZE, fmt, args);
dbg_print("%s", buf);
dbg_print("\nC%ld Halting.\n\n", apic_current_id());
DEBUG_EXIT
va_end(args);
dbg_panic_halt();
}
|