1 | /* $NetBSD: xen_debug.c,v 1.9 2016/07/07 06:55:40 msaitoh Exp $ */ |
2 | |
3 | /* |
4 | * |
5 | * Copyright (c) 2004 Christian Limpach. |
6 | * All rights reserved. |
7 | * |
8 | * Redistribution and use in source and binary forms, with or without |
9 | * modification, are permitted provided that the following conditions |
10 | * are met: |
11 | * 1. Redistributions of source code must retain the above copyright |
12 | * notice, this list of conditions and the following disclaimer. |
13 | * 2. Redistributions in binary form must reproduce the above copyright |
14 | * notice, this list of conditions and the following disclaimer in the |
15 | * documentation and/or other materials provided with the distribution. |
16 | * |
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | */ |
28 | |
29 | /* |
30 | * |
31 | * Copyright (c) 2002-2003, K A Fraser & R Neugebauer |
32 | * |
33 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
34 | * of this software and associated documentation files (the "Software"), to |
35 | * deal in the Software without restriction, including without limitation the |
36 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
37 | * sell copies of the Software, and to permit persons to whom the Software is |
38 | * furnished to do so, subject to the following conditions: |
39 | * |
40 | * The above copyright notice and this permission notice shall be included in |
41 | * all copies or substantial portions of the Software. |
42 | * |
43 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
44 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
45 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
46 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
47 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
48 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
49 | * DEALINGS IN THE SOFTWARE. |
50 | */ |
51 | |
52 | |
53 | #include <sys/cdefs.h> |
54 | __KERNEL_RCSID(0, "$NetBSD: xen_debug.c,v 1.9 2016/07/07 06:55:40 msaitoh Exp $" ); |
55 | |
56 | #define XENDEBUG |
57 | |
58 | #include <sys/param.h> |
59 | #include <sys/systm.h> |
60 | |
61 | #include <xen/xen.h> |
62 | #include <xen/hypervisor.h> |
63 | |
64 | #ifdef XENDEBUG |
65 | |
66 | #define PRINTK_BUFSIZE 1024 |
67 | void |
68 | printk(const char *fmt, ...) |
69 | { |
70 | va_list ap; |
71 | int ret; |
72 | static char buf[PRINTK_BUFSIZE]; |
73 | |
74 | va_start(ap, fmt); |
75 | ret = vsnprintf(buf, PRINTK_BUFSIZE - 1, fmt, ap); |
76 | va_end(ap); |
77 | buf[ret] = 0; |
78 | (void)HYPERVISOR_console_io(CONSOLEIO_write, ret, buf); |
79 | } |
80 | |
81 | void |
82 | vprintk(const char *fmt, va_list ap) |
83 | { |
84 | int ret; |
85 | static char buf[PRINTK_BUFSIZE]; |
86 | |
87 | ret = vsnprintf(buf, PRINTK_BUFSIZE - 1, fmt, ap); |
88 | buf[ret] = 0; |
89 | (void)HYPERVISOR_console_io(CONSOLEIO_write, ret, buf); |
90 | } |
91 | |
92 | #endif |
93 | |
94 | #ifdef XENDEBUG_LOW |
95 | |
96 | int xen_once = 0; |
97 | |
98 | void hypervisor_callback(void); |
99 | void failsafe_callback(void); |
100 | |
101 | void xen_dbglow_init(void); |
102 | void |
103 | xen_dbglow_init(void) |
104 | { |
105 | start_info_t *si; |
106 | #if 0 |
107 | int i; |
108 | #endif |
109 | |
110 | si = &xen_start_info; |
111 | |
112 | HYPERVISOR_set_callbacks( |
113 | __KERNEL_CS, (unsigned long)hypervisor_callback, |
114 | __KERNEL_CS, (unsigned long)failsafe_callback); |
115 | |
116 | trap_init(); |
117 | |
118 | /* __sti(); */ |
119 | |
120 | /* print out some useful information */ |
121 | printk(version); |
122 | printk("start_info: %p\n" , si); |
123 | printk(" nr_pages: %lu" , si->nr_pages); |
124 | printk(" shared_inf: %p (was %p)\n" , HYPERVISOR_shared_info, |
125 | si->shared_info); |
126 | printk(" pt_base: %p" , (void *)si->pt_base); |
127 | printk(" mod_start: 0x%lx\n" , si->mod_start); |
128 | printk(" mod_len: %lu\n" , si->mod_len); |
129 | #if 0 |
130 | printk(" net_rings: " ); |
131 | for (i = 0; i < MAX_DOMAIN_VIFS; i++) { |
132 | if (si->net_rings[i] == 0) |
133 | break; |
134 | printk(" %lx" , si->net_rings[i]); |
135 | }; |
136 | printk("\n" ); |
137 | printk(" blk_ring: 0x%lx\n" , si->blk_ring); |
138 | #endif |
139 | printk(" dom_id: %d\n" , si->dom_id); |
140 | printk(" flags: 0x%lx\n" , si->flags); |
141 | printk(" cmd_line: %s\n" , si->cmd_line ? |
142 | (const char *)si->cmd_line : "NULL" ); |
143 | } |
144 | |
145 | |
146 | void xen_dbg0(char *); |
147 | void |
148 | xen_dbg0(char *end) |
149 | { |
150 | struct cpu_info *ci; |
151 | |
152 | ci = &cpu_info_primary; |
153 | if (xen_once) |
154 | printk("xencpu level %d ipending %08x master %08x\n" , |
155 | ci->ci_ilevel, ci->ci_ipending, |
156 | HYPERVISOR_shared_info->events_mask); |
157 | /* ipending %08x imask %08x iunmask %08x */ |
158 | /* ci->ci_imask[IPL_NET], ci->ci_iunmask[IPL_NET]); */ |
159 | } |
160 | |
161 | void xen_dbg1(void *esp, int ss); |
162 | void |
163 | xen_dbg1(void *esp, int ss) |
164 | { |
165 | #if 1 |
166 | struct cpu_info *ci; |
167 | |
168 | ci = &cpu_info_primary; |
169 | if (xen_once) |
170 | printk("xenhighlevel %d ipending %08x master %08x events %08x\n" , |
171 | ci->ci_ilevel, ci->ci_ipending, |
172 | HYPERVISOR_shared_info->events_mask, HYPERVISOR_shared_info->events); |
173 | #else |
174 | printk("stack switch %p %d/%d, sp %p\n" , esp, ss, IDXSEL(ss), &ss); |
175 | #endif |
176 | } |
177 | |
178 | void xen_dbg2(void); |
179 | void |
180 | xen_dbg2(void) |
181 | { |
182 | if (xen_once) |
183 | printk("xen_dbg2\n" ); |
184 | } |
185 | |
186 | void xen_dbg3(void *, void *); |
187 | void |
188 | xen_dbg3(void *ss, void *esp) |
189 | { |
190 | if (xen_once) |
191 | printk("xen_dbg3 %p %p\n" , ss, esp); |
192 | } |
193 | |
194 | void xen_dbg4(void *); |
195 | void |
196 | xen_dbg4(void *esi) |
197 | { |
198 | |
199 | printk("xen_dbg4 %p\n" , esi); |
200 | for(;;); |
201 | } |
202 | |
203 | |
204 | |
205 | |
206 | static void do_exit(void); |
207 | |
208 | /* |
209 | * These are assembler stubs in vector.S. |
210 | * They are the actual entry points for virtual exceptions. |
211 | */ |
212 | void divide_error(void); |
213 | void debug(void); |
214 | void int3(void); |
215 | void overflow(void); |
216 | void bounds(void); |
217 | void invalid_op(void); |
218 | void device_not_available(void); |
219 | void double_fault(void); |
220 | void coprocessor_segment_overrun(void); |
221 | void invalid_TSS(void); |
222 | void segment_not_present(void); |
223 | void stack_segment(void); |
224 | void general_protection(void); |
225 | void page_fault(void); |
226 | void coprocessor_error(void); |
227 | void simd_coprocessor_error(void); |
228 | void alignment_check(void); |
229 | void spurious_interrupt_bug(void); |
230 | void machine_check(void); |
231 | |
232 | static void |
233 | dump_regs(struct pt_regs *regs) |
234 | { |
235 | int in_kernel = 1; |
236 | unsigned long esp; |
237 | unsigned short ss; |
238 | |
239 | esp = (unsigned long) (®s->esp); |
240 | ss = __KERNEL_DS; |
241 | if (regs->xcs & 2) { |
242 | in_kernel = 0; |
243 | esp = regs->esp; |
244 | ss = regs->xss & 0xffff; |
245 | } |
246 | printf("EIP: %04x:[<%08lx>]\n" , |
247 | 0xffff & regs->xcs, regs->eip); |
248 | printf("EFLAGS: %08lx\n" ,regs->eflags); |
249 | printf("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n" , |
250 | regs->eax, regs->ebx, regs->ecx, regs->edx); |
251 | printf("esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n" , |
252 | regs->esi, regs->edi, regs->ebp, esp); |
253 | printf("ds: %04x es: %04x ss: %04x\n" , |
254 | regs->xds & 0xffff, regs->xes & 0xffff, ss); |
255 | printf("\n" ); |
256 | } |
257 | |
258 | |
259 | static inline void |
260 | dump_code(unsigned eip) |
261 | { |
262 | unsigned *ptr = (unsigned *)eip; |
263 | int x; |
264 | |
265 | printk("Bytes at eip:\n" ); |
266 | for (x = -4; x < 5; x++) |
267 | printf("%x" , ptr[x]); |
268 | } |
269 | |
270 | |
271 | /* |
272 | * C handlers here have their parameter-list constructed by the |
273 | * assembler stubs above. Each one gets a pointer to a list |
274 | * of register values (to be restored at end of exception). |
275 | * Some will also receive an error code -- this is the code that |
276 | * was generated by the processor for the underlying real exception. |
277 | * |
278 | * Note that the page-fault exception is special. It also receives |
279 | * the faulting linear address. Normally this would be found in |
280 | * register CR2, but that is not accessible in a virtualised OS. |
281 | */ |
282 | |
283 | static void inline |
284 | do_trap(int trapnr, char *str, struct pt_regs *regs, long error_code) |
285 | { |
286 | |
287 | printk("FATAL: Unhandled Trap (see mini-os:traps.c)" ); |
288 | printf("%d %s" , trapnr, str); |
289 | dump_regs(regs); |
290 | dump_code(regs->eip); |
291 | |
292 | do_exit(); |
293 | } |
294 | |
295 | #define DO_ERROR(trapnr, str, name) \ |
296 | void do_##name(struct pt_regs *regs, long error_code); \ |
297 | void do_##name(struct pt_regs *regs, long error_code) \ |
298 | { \ |
299 | do_trap(trapnr, str, regs, error_code); \ |
300 | } |
301 | |
302 | #define DO_ERROR_INFO(trapnr, str, name, sicode, siaddr) \ |
303 | void do_##name(struct pt_regs *regs, long error_code); \ |
304 | void do_##name(struct pt_regs *regs, long error_code) \ |
305 | { \ |
306 | do_trap(trapnr, str, regs, error_code); \ |
307 | } |
308 | |
309 | DO_ERROR_INFO( 0, "divide error" , divide_error, FPE_INTDIV, regs->eip) |
310 | DO_ERROR( 3, "int3" , int3) |
311 | DO_ERROR( 4, "overflow" , overflow) |
312 | DO_ERROR( 5, "bounds" , bounds) |
313 | DO_ERROR_INFO( 6, "invalid operand" , invalid_op, ILL_ILLOPN, regs->eip) |
314 | DO_ERROR( 7, "device not available" , device_not_available) |
315 | DO_ERROR( 8, "double fault" , double_fault) |
316 | DO_ERROR( 9, "coprocessor segment overrun" , coprocessor_segment_overrun) |
317 | DO_ERROR(10, "invalid TSS" , invalid_TSS) |
318 | DO_ERROR(11, "segment not present" , segment_not_present) |
319 | DO_ERROR(12, "stack segment" , stack_segment) |
320 | DO_ERROR_INFO(17, "alignment check" , alignment_check, BUS_ADRALN, 0) |
321 | DO_ERROR(18, "machine check" , machine_check) |
322 | |
323 | void do_page_fault(struct pt_regs *, long, unsigned long); |
324 | void |
325 | do_page_fault(struct pt_regs *regs, long error_code, unsigned long address) |
326 | { |
327 | |
328 | printk("Page fault\n" ); |
329 | printk("Address: 0x%lx" , address); |
330 | printk("Error Code: 0x%lx" , error_code); |
331 | printk("eip: \t 0x%lx" , regs->eip); |
332 | do_exit(); |
333 | } |
334 | |
335 | void do_general_protection(struct pt_regs *, long); |
336 | void |
337 | do_general_protection(struct pt_regs *regs, long error_code) |
338 | { |
339 | |
340 | HYPERVISOR_shared_info->events_mask = 0; |
341 | printk("GPF\n" ); |
342 | printk("Error Code: 0x%lx" , error_code); |
343 | dump_regs(regs); |
344 | dump_code(regs->eip); |
345 | do_exit(); |
346 | } |
347 | |
348 | |
349 | void do_debug(struct pt_regs *, long); |
350 | void |
351 | do_debug(struct pt_regs *regs, long error_code) |
352 | { |
353 | |
354 | printk("Debug exception\n" ); |
355 | #define TF_MASK 0x100 |
356 | regs->eflags &= ~TF_MASK; |
357 | dump_regs(regs); |
358 | do_exit(); |
359 | } |
360 | |
361 | |
362 | |
363 | void do_coprocessor_error(struct pt_regs *, long); |
364 | void |
365 | do_coprocessor_error(struct pt_regs *regs, long error_code) |
366 | { |
367 | |
368 | printk("Copro error\n" ); |
369 | dump_regs(regs); |
370 | dump_code(regs->eip); |
371 | do_exit(); |
372 | } |
373 | |
374 | void simd_math_error(void *); |
375 | void |
376 | simd_math_error(void *eip) |
377 | { |
378 | |
379 | printk("SIMD error\n" ); |
380 | } |
381 | |
382 | void do_simd_coprocessor_error(struct pt_regs *, long); |
383 | void |
384 | do_simd_coprocessor_error(struct pt_regs *regs, long error_code) |
385 | { |
386 | |
387 | printk("SIMD copro error\n" ); |
388 | } |
389 | |
390 | void do_spurious_interrupt_bug(struct pt_regs *, long); |
391 | void |
392 | do_spurious_interrupt_bug(struct pt_regs *regs, long error_code) |
393 | { |
394 | } |
395 | |
396 | static void |
397 | do_exit(void) |
398 | { |
399 | |
400 | HYPERVISOR_exit(); |
401 | } |
402 | |
403 | /* |
404 | * Submit a virtual IDT to teh hypervisor. This consists of tuples |
405 | * (interrupt vector, privilege ring, CS:EIP of handler). |
406 | * The 'privilege ring' field specifies the least-privileged ring that |
407 | * can trap to that vector using a software-interrupt instruction (INT). |
408 | */ |
409 | static trap_info_t trap_table[] = { |
410 | { 0, 0, __KERNEL_CS, (unsigned long)divide_error }, |
411 | { 1, 0, __KERNEL_CS, (unsigned long)debug }, |
412 | { 3, 3, __KERNEL_CS, (unsigned long)int3 }, |
413 | { 4, 3, __KERNEL_CS, (unsigned long)overflow }, |
414 | { 5, 3, __KERNEL_CS, (unsigned long)bounds }, |
415 | { 6, 0, __KERNEL_CS, (unsigned long)invalid_op }, |
416 | { 7, 0, __KERNEL_CS, (unsigned long)device_not_available }, |
417 | { 8, 0, __KERNEL_CS, (unsigned long)double_fault }, |
418 | { 9, 0, __KERNEL_CS, (unsigned long)coprocessor_segment_overrun }, |
419 | { 10, 0, __KERNEL_CS, (unsigned long)invalid_TSS }, |
420 | { 11, 0, __KERNEL_CS, (unsigned long)segment_not_present }, |
421 | { 12, 0, __KERNEL_CS, (unsigned long)stack_segment }, |
422 | { 13, 0, __KERNEL_CS, (unsigned long)general_protection }, |
423 | { 14, 0, __KERNEL_CS, (unsigned long)page_fault }, |
424 | { 15, 0, __KERNEL_CS, (unsigned long)spurious_interrupt_bug }, |
425 | { 16, 0, __KERNEL_CS, (unsigned long)coprocessor_error }, |
426 | { 17, 0, __KERNEL_CS, (unsigned long)alignment_check }, |
427 | { 18, 0, __KERNEL_CS, (unsigned long)machine_check }, |
428 | { 19, 0, __KERNEL_CS, (unsigned long)simd_coprocessor_error }, |
429 | { 0, 0, 0, 0 } |
430 | }; |
431 | |
432 | void |
433 | trap_init(void) |
434 | { |
435 | |
436 | HYPERVISOR_set_trap_table(trap_table); |
437 | } |
438 | #endif |
439 | |