#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)
{
die_if_kernel("Divide Error", interrupted_instruction);
signal_self(SIGFPE);
}
void do_debug(const struct interrupted_instruction_struct *interrupted_instruction)
{
die_if_kernel("Debug Exception", interrupted_instruction);
}
void do_nonmaskable_interrupt()
{
}
void do_breakpoint(const struct interrupted_instruction_struct *interrupted_instruction)
{
die_if_kernel("Breakpoint", interrupted_instruction);
}
void do_overflow(const struct interrupted_instruction_struct *interrupted_instruction)
{
die_if_kernel("Overflow", interrupted_instruction);
signal_self(SIGFPE);
}
void do_bounds_check(const struct interrupted_instruction_struct *interrupted_instruction)
{
die_if_kernel("Bounds Check", interrupted_instruction);
signal_self(SIGSEGV);
}
void do_invalid_opcode(const struct interrupted_instruction_struct *interrupted_instruction)
{
die_if_kernel("Invalid Opcode", interrupted_instruction);
signal_self(SIGILL);
}
void do_device_not_available(const struct interrupted_instruction_struct *interrupted_instruction)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
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)
{
die_if_kernel("Coprocessor Error", interrupted_instruction);
signal_self(SIGFPE);
}
void do_alignment_check(const struct interrupted_instruction_struct *interrupted_instruction)
{
die_if_kernel("Alignement Check", interrupted_instruction);
signal_self(SIGBUS);
}
void do_machine_check(const struct interrupted_instruction_struct *interrupted_instruction)
{
die_if_kernel("Machine Check", interrupted_instruction);
signal_self(SIGSEGV);
}