/* Copyright (C) 2008 Emmanuel Varoquaux This file is part of XOS. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "current.h" #include #include #include #include #include #include #include #include static inline int from_kernel_mode(const struct interrupted_instruction_struct *interrupted_instruction) { struct sel_data_struct sel_data; get_sel(&interrupted_instruction->cs, &sel_data); return !sel_data.rpl; } static void print_exception(const char *msg) { printk("Exception in kernel mode: %s\n", msg); } static void print_interrupted_instruction(const struct interrupted_instruction_struct *interrupted_instruction) { printk("Location: %.4hx:%.8lx\n", interrupted_instruction->cs, interrupted_instruction->eip); printk("Flags: %.8lx\n", interrupted_instruction->eflags); } static void print_error_code(unsigned long error_code) { printk("Error code: %.8lx\n", error_code); } static void print_address(unsigned long address) { printk("Address: %.8lx\n", address); } static void die_if_kernel(const char *msg, const struct interrupted_instruction_struct *interrupted_instruction) { if (from_kernel_mode(interrupted_instruction)) { print_exception(msg); print_interrupted_instruction(interrupted_instruction); die(); } } static void die_if_kernel_error_code(const char *msg, const struct interrupted_instruction_struct *interrupted_instruction, unsigned long error_code) { if (from_kernel_mode(interrupted_instruction)) { print_exception(msg); print_interrupted_instruction(interrupted_instruction); print_error_code(error_code); die(); } } static void die_if_kernel_page_fault(const struct interrupted_instruction_struct *interrupted_instruction, unsigned long error_code, unsigned long address) { if (from_kernel_mode(interrupted_instruction)) { print_exception("Page fault"); print_interrupted_instruction(interrupted_instruction); print_error_code(error_code); print_address(address); die(); } } void do_divide_error(const struct interrupted_instruction_struct *interrupted_instruction) /* Divide Error (fault) */ { die_if_kernel("Divide Error", interrupted_instruction); signal_self(SIGFPE); } void do_debug(const struct interrupted_instruction_struct *interrupted_instruction) /* Debug Exceptions (trap/fault) */ { die_if_kernel("Debug Exception", interrupted_instruction); } void do_nonmaskable_interrupt() /* Nonmaskable Interrupt (NMI) */ { /* ignore */ } void do_breakpoint(const struct interrupted_instruction_struct *interrupted_instruction) /* Breakpoint (trap) */ { die_if_kernel("Breakpoint", interrupted_instruction); } void do_overflow(const struct interrupted_instruction_struct *interrupted_instruction) /* Overflow (trap) */ { die_if_kernel("Overflow", interrupted_instruction); signal_self(SIGFPE); } void do_bounds_check(const struct interrupted_instruction_struct *interrupted_instruction) /* Bounds Check (fault) */ { die_if_kernel("Bounds Check", interrupted_instruction); signal_self(SIGSEGV); } void do_invalid_opcode(const struct interrupted_instruction_struct *interrupted_instruction) /* Invalid Opcode (fault) */ { die_if_kernel("Invalid Opcode", interrupted_instruction); signal_self(SIGILL); } void do_device_not_available(const struct interrupted_instruction_struct *interrupted_instruction) /* Coprocessor Not Available (fault) */ { die_if_kernel("Coprocessor Not Available", interrupted_instruction); signal_self(SIGFPE); } void do_double_fault(const struct interrupted_instruction_struct *interrupted_instruction, unsigned long error_code) /* Double Fault (abort, error code) */ { die_if_kernel_error_code("Double Fault", interrupted_instruction, error_code); signal_self(SIGSEGV); } void do_coprocessor_segment_overrun(const struct interrupted_instruction_struct *interrupted_instruction, unsigned long error_code) /* Coprocessor Segment Overrun (abort, error code) */ { die_if_kernel_error_code("Coprocessor Segment Overrun", interrupted_instruction, error_code); signal_self(SIGFPE); } void do_invalid_tss(const struct interrupted_instruction_struct *interrupted_instruction, unsigned long error_code) /* Invalid TSS (fault, error code) */ { die_if_kernel_error_code("Invalid TSS", interrupted_instruction, error_code); signal_self(SIGSEGV); } void do_segment_not_present(const struct interrupted_instruction_struct *interrupted_instruction, unsigned long error_code) /* Segment Not Present (fault, error code) */ { die_if_kernel_error_code("Segment Not Present", interrupted_instruction, error_code); signal_self(SIGBUS); } void do_stack_segment_fault(const struct interrupted_instruction_struct *interrupted_instruction, unsigned long error_code) /* Stack Fault (fault, error code) */ { die_if_kernel_error_code("Stack Fault", interrupted_instruction, error_code); signal_self(SIGBUS); } void do_general_protection(const struct interrupted_instruction_struct *interrupted_instruction, unsigned long error_code) /* General Protection Exception (fault/abort, error code) */ { die_if_kernel_error_code("General Protection Exception", interrupted_instruction, error_code); signal_self(SIGSEGV); } void do_page_fault(const struct interrupted_instruction_struct *interrupted_instruction, unsigned long error_code) /* Page Fault (fault, error code) */ { unsigned long laddr; struct page_fault_error_code_data_struct error_code_data; int status; get_page_fault_laddr(laddr); die_if_kernel_page_fault(interrupted_instruction, error_code, laddr); get_page_fault_error_code(&error_code, &error_code_data); if (!error_code_data.mode) /* supervisor mode */ panic("Strange, the processor is executing a user code segment in kernel mode"); if ((status = handle_page_fault(error_code_data.cause ? PF_PROTECTION_VIOLATION : PF_NOT_PRESENT, error_code_data.access ? PF_WRITE : PF_READ, interrupted_instruction->esp, laddr))) { switch (status) { case PF_MAPERR: case PF_ACCERR: signal_self(SIGSEGV); break; case PF_ADRERR: default: signal_self(SIGBUS); } } } void do_coprocessor_error(const struct interrupted_instruction_struct *interrupted_instruction) /* Coprocessor Error (fault) */ { die_if_kernel("Coprocessor Error", interrupted_instruction); signal_self(SIGFPE); } void do_alignment_check(const struct interrupted_instruction_struct *interrupted_instruction) /* Alignement Check (486) */ { die_if_kernel("Alignement Check", interrupted_instruction); signal_self(SIGBUS); } void do_machine_check(const struct interrupted_instruction_struct *interrupted_instruction) /* Machine Check (Pentium) */ { die_if_kernel("Machine Check", interrupted_instruction); signal_self(SIGSEGV); }