/* 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);
}