mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
213 lines
6.5 KiB
C
213 lines
6.5 KiB
C
|
|
#include <os.h>
|
|
#include <traps.h>
|
|
#include <hypervisor.h>
|
|
#include <mm.h>
|
|
#include <lib.h>
|
|
|
|
/*
|
|
* These are assembler stubs in entry.S.
|
|
* They are the actual entry points for virtual exceptions.
|
|
*/
|
|
void divide_error(void);
|
|
void debug(void);
|
|
void int3(void);
|
|
void overflow(void);
|
|
void bounds(void);
|
|
void invalid_op(void);
|
|
void device_not_available(void);
|
|
void coprocessor_segment_overrun(void);
|
|
void invalid_TSS(void);
|
|
void segment_not_present(void);
|
|
void stack_segment(void);
|
|
void general_protection(void);
|
|
void page_fault(void);
|
|
void coprocessor_error(void);
|
|
void simd_coprocessor_error(void);
|
|
void alignment_check(void);
|
|
void spurious_interrupt_bug(void);
|
|
void machine_check(void);
|
|
|
|
|
|
extern void do_exit(void);
|
|
|
|
void dump_regs(struct pt_regs *regs)
|
|
{
|
|
unsigned long esp;
|
|
unsigned short ss;
|
|
|
|
#ifdef __x86_64__
|
|
esp = regs->rsp;
|
|
ss = regs->xss;
|
|
#else
|
|
esp = (unsigned long) (®s->esp);
|
|
ss = __KERNEL_DS;
|
|
if (regs->xcs & 2) {
|
|
printk("CS is true, esp is %x\n", regs->esp);
|
|
esp = regs->esp;
|
|
ss = regs->xss & 0xffff;
|
|
}
|
|
#endif
|
|
printf("EIP: %04x:[<%p>]\n",
|
|
0xffff & regs->xcs , regs->eip);
|
|
printf("EFLAGS: %p\n",regs->eflags);
|
|
printf("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n",
|
|
regs->eax, regs->ebx, regs->ecx, regs->edx);
|
|
printf("esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n",
|
|
regs->esi, regs->edi, regs->ebp, esp);
|
|
#ifdef __x86_64__
|
|
printf("r8 : %p r9 : %p r10: %p r11: %p\n",
|
|
regs->r8, regs->r9, regs->r10, regs->r11);
|
|
printf("r12: %p r13: %p r14: %p r15: %p\n",
|
|
regs->r12, regs->r13, regs->r14, regs->r15);
|
|
#endif
|
|
printf("ds: %04x es: %04x ss: %04x\n",
|
|
regs->xds & 0xffff, regs->xes & 0xffff, ss);
|
|
}
|
|
|
|
|
|
static void do_trap(int trapnr, char *str, struct pt_regs * regs, unsigned long error_code)
|
|
{
|
|
printk("FATAL: Unhandled Trap %d (%s), error code=0x%lx\n", trapnr, str, error_code);
|
|
printk("Regs address %p\n", regs);
|
|
dump_regs(regs);
|
|
do_exit();
|
|
}
|
|
|
|
#define DO_ERROR(trapnr, str, name) \
|
|
void do_##name(struct pt_regs * regs, unsigned long error_code) \
|
|
{ \
|
|
do_trap(trapnr, str, regs, error_code); \
|
|
}
|
|
|
|
#define DO_ERROR_INFO(trapnr, str, name, sicode, siaddr) \
|
|
void do_##name(struct pt_regs * regs, unsigned long error_code) \
|
|
{ \
|
|
do_trap(trapnr, str, regs, error_code); \
|
|
}
|
|
|
|
DO_ERROR_INFO( 0, "divide error", divide_error, FPE_INTDIV, regs->eip)
|
|
DO_ERROR( 3, "int3", int3)
|
|
DO_ERROR( 4, "overflow", overflow)
|
|
DO_ERROR( 5, "bounds", bounds)
|
|
DO_ERROR_INFO( 6, "invalid operand", invalid_op, ILL_ILLOPN, regs->eip)
|
|
DO_ERROR( 7, "device not available", device_not_available)
|
|
DO_ERROR( 9, "coprocessor segment overrun", coprocessor_segment_overrun)
|
|
DO_ERROR(10, "invalid TSS", invalid_TSS)
|
|
DO_ERROR(11, "segment not present", segment_not_present)
|
|
DO_ERROR(12, "stack segment", stack_segment)
|
|
DO_ERROR_INFO(17, "alignment check", alignment_check, BUS_ADRALN, 0)
|
|
DO_ERROR(18, "machine check", machine_check)
|
|
|
|
void do_page_fault(struct pt_regs *regs, unsigned long error_code,
|
|
unsigned long addr)
|
|
{
|
|
printk("Page fault at linear address %p\n", addr);
|
|
dump_regs(regs);
|
|
#ifdef __x86_64__
|
|
{
|
|
unsigned long *tab = (unsigned long *)start_info.pt_base;
|
|
unsigned long page;
|
|
|
|
printk("Pagetable walk from %p:\n", tab);
|
|
|
|
page = tab[l4_table_offset(addr)];
|
|
tab = __va(mfn_to_pfn(pte_to_mfn(page)) << PAGE_SHIFT);
|
|
printk(" L4 = %p (%p)\n", page, tab);
|
|
if ( !(page & AGERESENT) )
|
|
goto out;
|
|
|
|
page = tab[l3_table_offset(addr)];
|
|
tab = __va(mfn_to_pfn(pte_to_mfn(page)) << PAGE_SHIFT);
|
|
printk(" L3 = %p (%p)\n", page, tab);
|
|
if ( !(page & AGERESENT) )
|
|
goto out;
|
|
|
|
page = tab[l2_table_offset(addr)];
|
|
tab = __va(mfn_to_pfn(pte_to_mfn(page)) << PAGE_SHIFT);
|
|
printk(" L2 = %p (%p) %s\n", page, tab,
|
|
(page & AGESE) ? "(2MB)" : "");
|
|
if ( !(page & AGERESENT) || (page & AGESE) )
|
|
goto out;
|
|
|
|
page = tab[l1_table_offset(addr)];
|
|
printk(" L1 = %p\n", page);
|
|
}
|
|
#endif
|
|
do_exit();
|
|
}
|
|
|
|
void do_general_protection(struct pt_regs *regs, long error_code)
|
|
{
|
|
printk("GPF %p, error_code=%lx\n", regs, error_code);
|
|
dump_regs(regs);
|
|
do_exit();
|
|
}
|
|
|
|
|
|
void do_debug(struct pt_regs * regs)
|
|
{
|
|
printk("Debug exception\n");
|
|
#define TF_MASK 0x100
|
|
regs->eflags &= ~TF_MASK;
|
|
dump_regs(regs);
|
|
do_exit();
|
|
}
|
|
|
|
void do_coprocessor_error(struct pt_regs * regs)
|
|
{
|
|
printk("Copro error\n");
|
|
dump_regs(regs);
|
|
do_exit();
|
|
}
|
|
|
|
void simd_math_error(void *eip)
|
|
{
|
|
printk("SIMD error\n");
|
|
}
|
|
|
|
void do_simd_coprocessor_error(struct pt_regs * regs)
|
|
{
|
|
printk("SIMD copro error\n");
|
|
}
|
|
|
|
void do_spurious_interrupt_bug(struct pt_regs * regs)
|
|
{
|
|
}
|
|
|
|
/*
|
|
* Submit a virtual IDT to teh hypervisor. This consists of tuples
|
|
* (interrupt vector, privilege ring, CS:EIP of handler).
|
|
* The 'privilege ring' field specifies the least-privileged ring that
|
|
* can trap to that vector using a software-interrupt instruction (INT).
|
|
*/
|
|
static trap_info_t trap_table[] = {
|
|
{ 0, 0, __KERNEL_CS, (unsigned long)divide_error },
|
|
{ 1, 0, __KERNEL_CS, (unsigned long)debug },
|
|
{ 3, 3, __KERNEL_CS, (unsigned long)int3 },
|
|
{ 4, 3, __KERNEL_CS, (unsigned long)overflow },
|
|
{ 5, 3, __KERNEL_CS, (unsigned long)bounds },
|
|
{ 6, 0, __KERNEL_CS, (unsigned long)invalid_op },
|
|
{ 7, 0, __KERNEL_CS, (unsigned long)device_not_available },
|
|
{ 9, 0, __KERNEL_CS, (unsigned long)coprocessor_segment_overrun },
|
|
{ 10, 0, __KERNEL_CS, (unsigned long)invalid_TSS },
|
|
{ 11, 0, __KERNEL_CS, (unsigned long)segment_not_present },
|
|
{ 12, 0, __KERNEL_CS, (unsigned long)stack_segment },
|
|
{ 13, 0, __KERNEL_CS, (unsigned long)general_protection },
|
|
{ 14, 0, __KERNEL_CS, (unsigned long)page_fault },
|
|
{ 15, 0, __KERNEL_CS, (unsigned long)spurious_interrupt_bug },
|
|
{ 16, 0, __KERNEL_CS, (unsigned long)coprocessor_error },
|
|
{ 17, 0, __KERNEL_CS, (unsigned long)alignment_check },
|
|
{ 18, 0, __KERNEL_CS, (unsigned long)machine_check },
|
|
{ 19, 0, __KERNEL_CS, (unsigned long)simd_coprocessor_error },
|
|
{ 0, 0, 0, 0 }
|
|
};
|
|
|
|
|
|
|
|
void trap_init(void)
|
|
{
|
|
HYPERVISOR_set_trap_table(trap_table);
|
|
}
|
|
|