169 lines
3.8 KiB
C
169 lines
3.8 KiB
C
/*
|
|
Copyright (C) 2015-2019 The University of Notre Dame
|
|
This software is distributed under the GNU General Public License.
|
|
See the file LICENSE for details.
|
|
*/
|
|
|
|
#include "interrupt.h"
|
|
#include "console.h"
|
|
#include "pic.h"
|
|
#include "process.h"
|
|
#include "kernelcore.h"
|
|
#include "x86.h"
|
|
|
|
static interrupt_handler_t interrupt_handler_table[48];
|
|
static uint32_t interrupt_count[48];
|
|
static uint8_t interrupt_spurious[48];
|
|
|
|
static const char *exception_names[] = {
|
|
"division by zero",
|
|
"debug exception",
|
|
"nonmaskable interrupt",
|
|
"breakpoint",
|
|
"overflow",
|
|
"bounds check",
|
|
"invalid instruction",
|
|
"coprocessor error",
|
|
"double fault",
|
|
"copressor overrun",
|
|
"invalid task",
|
|
"segment not present",
|
|
"stack exception",
|
|
"general protection fault",
|
|
"page fault",
|
|
"unknown",
|
|
"coprocessor error"
|
|
};
|
|
|
|
static void unknown_exception(int i, int code)
|
|
{
|
|
unsigned vaddr; // virtual address trying to be accessed
|
|
unsigned paddr; // physical address
|
|
unsigned esp; // stack pointer
|
|
|
|
if(i==14) {
|
|
asm("mov %%cr2, %0" : "=r" (vaddr) ); // virtual address trying to be accessed
|
|
esp = ((struct x86_stack *)(current->kstack_top - sizeof(struct x86_stack)))->esp; // stack pointer of the process that raised the exception
|
|
// Check if the requested memory is in the stack or data
|
|
int data_access = vaddr < current->vm_data_size;
|
|
|
|
// Subtract 128 from esp because of the red-zone
|
|
// According to https:gcc.gnu.org, the red zone is a 128-byte area beyond
|
|
// the stack pointer that will not be modified by signal or interrupt handlers
|
|
// and therefore can be used for temporary data without adjusting the stack pointer.
|
|
int stack_access = vaddr >= esp - 128;
|
|
|
|
// Check if the requested memory is already in use
|
|
int page_already_present = pagetable_getmap(current->pagetable,vaddr,&paddr,0);
|
|
|
|
// Check if page is already mapped (which will result from violating the permissions on page) or that
|
|
// we are accessing neither the stack nor the heap, or we are accessing both. If so, error
|
|
if (page_already_present || !(data_access ^ stack_access)) {
|
|
printf("interrupt: illegal page access at vaddr %x\n",vaddr);
|
|
process_dump(current);
|
|
process_exit(0);
|
|
} else {
|
|
// XXX update process->vm_stack_size when growing the stack.
|
|
pagetable_alloc(current->pagetable, vaddr, PAGE_SIZE, PAGE_FLAG_USER | PAGE_FLAG_READWRITE | PAGE_FLAG_CLEAR);
|
|
return;
|
|
}
|
|
} else {
|
|
printf("interrupt: exception %d: %s (code %x)\n", i, exception_names[i], code);
|
|
process_dump(current);
|
|
}
|
|
|
|
if(current) {
|
|
process_exit(0);
|
|
} else {
|
|
printf("interrupt: exception in kernel code!\n");
|
|
halt();
|
|
}
|
|
}
|
|
|
|
static void unknown_hardware(int i, int code)
|
|
{
|
|
if(!interrupt_spurious[i]) {
|
|
printf("interrupt: spurious interrupt %d\n", i);
|
|
}
|
|
interrupt_spurious[i]++;
|
|
}
|
|
|
|
void interrupt_register(int i, interrupt_handler_t handler)
|
|
{
|
|
interrupt_handler_table[i] = handler;
|
|
}
|
|
|
|
static void interrupt_acknowledge(int i)
|
|
{
|
|
if(i < 32) {
|
|
/* do nothing */
|
|
} else {
|
|
pic_acknowledge(i - 32);
|
|
}
|
|
}
|
|
|
|
void interrupt_init()
|
|
{
|
|
int i;
|
|
pic_init(32, 40);
|
|
for(i = 32; i < 48; i++) {
|
|
interrupt_disable(i);
|
|
interrupt_acknowledge(i);
|
|
}
|
|
for(i = 0; i < 32; i++) {
|
|
interrupt_handler_table[i] = unknown_exception;
|
|
interrupt_spurious[i] = 0;
|
|
interrupt_count[i] = 0;
|
|
}
|
|
for(i = 32; i < 48; i++) {
|
|
interrupt_handler_table[i] = unknown_hardware;
|
|
interrupt_spurious[i] = 0;
|
|
interrupt_count[i] = 0;
|
|
}
|
|
|
|
interrupt_unblock();
|
|
|
|
printf("interrupt: ready\n");
|
|
}
|
|
|
|
void interrupt_handler(int i, int code)
|
|
{
|
|
(interrupt_handler_table[i]) (i, code);
|
|
interrupt_acknowledge(i);
|
|
interrupt_count[i]++;
|
|
}
|
|
|
|
void interrupt_enable(int i)
|
|
{
|
|
if(i < 32) {
|
|
/* do nothing */
|
|
} else {
|
|
pic_enable(i - 32);
|
|
}
|
|
}
|
|
|
|
void interrupt_disable(int i)
|
|
{
|
|
if(i < 32) {
|
|
/* do nothing */
|
|
} else {
|
|
pic_disable(i - 32);
|
|
}
|
|
}
|
|
|
|
void interrupt_block()
|
|
{
|
|
asm("cli");
|
|
}
|
|
|
|
void interrupt_unblock()
|
|
{
|
|
asm("sti");
|
|
}
|
|
|
|
void interrupt_wait()
|
|
{
|
|
asm("sti");
|
|
asm("hlt");
|
|
}
|