View of xos/kernel/exceptions.c


XOS | Parent Directory | View | Download

/* 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 <http://www.gnu.org/licenses/>. */
 
#include "current.h"
 
#include <panic.h>
#include <printk.h>
#include <system.h>
#include <system_data_structs.h>
#include <it_stack_structs.h>
#include <asm.h>
#include <consts.h>
#include <enums.h>
 
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);
}