Very lost on how to catch a divide by zero interrupt in x64
Posted: Sun Jul 03, 2016 7:57 pm
I just got back into starting kernel dev after moving but I seem to have hit a wall with catching a divide by 0 exception.
my strategy was to statically allocate enough space for the first 16 interrupt descriptors, set all the present flags to 0, then put a handler for DE exception in IDT[0].
I still fault however when dividing by zero. I've attached the interrupt handling code, which is entered into by calling load_IDT();
interrupts.h:
interrupts.c:
Like i have in the comment at the bottom of that last file, I know that for keyboard support I will have to interface with the 8259 (which I think is the id for the dual PIC on x86). I'm not trying to go that far yet, just get these exceptions caught.
my strategy was to statically allocate enough space for the first 16 interrupt descriptors, set all the present flags to 0, then put a handler for DE exception in IDT[0].
I still fault however when dividing by zero. I've attached the interrupt handling code, which is entered into by calling load_IDT();
interrupts.h:
Code: Select all
#ifndef interrupts_h
#define interrupts_h
#include "ktype.h"
struct opts {
uint8_t ist_index : 3;
uint8_t reserved : 5;
uint8_t int_or_trap : 1;
uint8_t must_be_one : 3;
uint8_t must_be_zro : 1;
uint8_t privelage_l : 2;
uint8_t present : 1;
}__attribute__((packed));
typedef struct idt_entry {
uint16_t ptr_low;
uint16_t selector;
struct opts opts;
uint16_t ptr_mid;
uint32_t ptr_high;
uint32_t _zero;
}__attribute__((packed)) idt_entry_t;
typedef struct {
uint16_t max_byte;
uint64_t virt_start;
}__attribute__((packed)) descriptor_table_t;
idt_entry_t create_empty();
idt_entry_t create(uint16_t, size_t);
uint16_t cs();
struct opts *set_handler(uint8_t loc, size_t fn_ptr);
void load_IDT();
#endif
Code: Select all
#include "ktype.h"
#include "interrupts.h"
#include "libk.h"
idt_entry_t IDT[16];
static inline void _load_IDT(void* base, uint16_t size) {
// This function works in 32 and 64bit mode
struct {
uint16_t length;
void* base;
} __attribute__((packed)) IDTR = { size, base };
asm ( "lidt %0" : : "m"(IDTR) ); // let the compiler choose an addressing mode
}
void divide_by_zero_handler() {
for(;;);
}
void IDT_init() {
for(int i=0;i<16;i++) {
IDT[i] = create_empty();
}
}
void load_IDT() {
IDT_init();
struct opts *options = set_handler(0, (uint64_t)÷_by_zero_handler);
_load_IDT(IDT, sizeof(IDT)-1);
}
struct opts *set_handler(uint8_t loc, size_t fn_ptr) {
IDT[loc] = create(cs(), fn_ptr);
return (struct opts *)&(IDT[loc].opts);
}
idt_entry_t create(uint16_t gdt_selector, size_t fn_ptr) {
idt_entry_t result;
result.selector = gdt_selector;
result.ptr_low = (uint8_t)fn_ptr;
result.ptr_mid = (uint8_t)(fn_ptr >> 16);
result.ptr_high = (uint16_t)(fn_ptr >> 32);
result.opts.ist_index = 0;
result.opts.reserved = 0;
result.opts.int_or_trap = 0;
result.opts.must_be_one = 0x07;
result.opts.must_be_zro = 0;
result.opts.privelage_l = 0;
result.opts.present = 1;
return result;
}
idt_entry_t create_empty() {
idt_entry_t result;
memset(&result, 0, sizeof(idt_entry_t));
result.opts.must_be_one = 0x07;
return result;
}
inline uint16_t cs(void) {
uint16_t val;
asm volatile ( "mov %%cs, %0" : "=r"(val) );
return val;
}
//intel 8259 support later!
Like i have in the comment at the bottom of that last file, I know that for keyboard support I will have to interface with the 8259 (which I think is the id for the dual PIC on x86). I'm not trying to go that far yet, just get these exceptions caught.