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
67void
68printk(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
81void
82vprintk(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
96int xen_once = 0;
97
98void hypervisor_callback(void);
99void failsafe_callback(void);
100
101void xen_dbglow_init(void);
102void
103xen_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
146void xen_dbg0(char *);
147void
148xen_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
161void xen_dbg1(void *esp, int ss);
162void
163xen_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
178void xen_dbg2(void);
179void
180xen_dbg2(void)
181{
182 if (xen_once)
183 printk("xen_dbg2\n");
184}
185
186void xen_dbg3(void *, void *);
187void
188xen_dbg3(void *ss, void *esp)
189{
190 if (xen_once)
191 printk("xen_dbg3 %p %p\n", ss, esp);
192}
193
194void xen_dbg4(void *);
195void
196xen_dbg4(void *esi)
197{
198
199 printk("xen_dbg4 %p\n", esi);
200 for(;;);
201}
202
203
204
205
206static 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 */
212void divide_error(void);
213void debug(void);
214void int3(void);
215void overflow(void);
216void bounds(void);
217void invalid_op(void);
218void device_not_available(void);
219void double_fault(void);
220void coprocessor_segment_overrun(void);
221void invalid_TSS(void);
222void segment_not_present(void);
223void stack_segment(void);
224void general_protection(void);
225void page_fault(void);
226void coprocessor_error(void);
227void simd_coprocessor_error(void);
228void alignment_check(void);
229void spurious_interrupt_bug(void);
230void machine_check(void);
231
232static void
233dump_regs(struct pt_regs *regs)
234{
235 int in_kernel = 1;
236 unsigned long esp;
237 unsigned short ss;
238
239 esp = (unsigned long) (&regs->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
259static inline void
260dump_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
283static void inline
284do_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) \
296void do_##name(struct pt_regs *regs, long error_code); \
297void 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) \
303void do_##name(struct pt_regs *regs, long error_code); \
304void do_##name(struct pt_regs *regs, long error_code) \
305{ \
306 do_trap(trapnr, str, regs, error_code); \
307}
308
309DO_ERROR_INFO( 0, "divide error", divide_error, FPE_INTDIV, regs->eip)
310DO_ERROR( 3, "int3", int3)
311DO_ERROR( 4, "overflow", overflow)
312DO_ERROR( 5, "bounds", bounds)
313DO_ERROR_INFO( 6, "invalid operand", invalid_op, ILL_ILLOPN, regs->eip)
314DO_ERROR( 7, "device not available", device_not_available)
315DO_ERROR( 8, "double fault", double_fault)
316DO_ERROR( 9, "coprocessor segment overrun", coprocessor_segment_overrun)
317DO_ERROR(10, "invalid TSS", invalid_TSS)
318DO_ERROR(11, "segment not present", segment_not_present)
319DO_ERROR(12, "stack segment", stack_segment)
320DO_ERROR_INFO(17, "alignment check", alignment_check, BUS_ADRALN, 0)
321DO_ERROR(18, "machine check", machine_check)
322
323void do_page_fault(struct pt_regs *, long, unsigned long);
324void
325do_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
335void do_general_protection(struct pt_regs *, long);
336void
337do_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
349void do_debug(struct pt_regs *, long);
350void
351do_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
363void do_coprocessor_error(struct pt_regs *, long);
364void
365do_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
374void simd_math_error(void *);
375void
376simd_math_error(void *eip)
377{
378
379 printk("SIMD error\n");
380}
381
382void do_simd_coprocessor_error(struct pt_regs *, long);
383void
384do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
385{
386
387 printk("SIMD copro error\n");
388}
389
390void do_spurious_interrupt_bug(struct pt_regs *, long);
391void
392do_spurious_interrupt_bug(struct pt_regs *regs, long error_code)
393{
394}
395
396static void
397do_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 */
409static 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
432void
433trap_init(void)
434{
435
436 HYPERVISOR_set_trap_table(trap_table);
437}
438#endif
439