11 changed files with 296 additions and 50 deletions
@ -0,0 +1,98 @@ |
|||
#include <stddef.h> |
|||
#include <stdint.h> |
|||
|
|||
#include "../common.h" |
|||
#include "idt.h" |
|||
|
|||
|
|||
|
|||
typedef struct { |
|||
uint16_t size; |
|||
const void* offset; |
|||
} __packed IDTD; |
|||
|
|||
|
|||
typedef struct { |
|||
uint8_t gate_type: 4; |
|||
uint8_t z : 1; |
|||
uint8_t dpl : 2; |
|||
uint8_t p : 1; |
|||
} __packed type_attr_t; |
|||
|
|||
|
|||
static_assert(sizeof(type_attr_t) == 1); |
|||
|
|||
|
|||
typedef struct { |
|||
uint16_t offset_1; // offset bits 0..15
|
|||
uint16_t selector; // a code segment selector in GDT or LDT
|
|||
uint8_t ist; // bits 0..2 holds Interrupt
|
|||
// Stack Table offset, rest of bits zero.
|
|||
|
|||
type_attr_t type_attr; // type and attributes
|
|||
uint16_t offset_2; // offset bits 16..31
|
|||
uint32_t offset_3; // offset bits 32..63
|
|||
uint32_t zero; // reserved
|
|||
} __packed IDTE; |
|||
|
|||
|
|||
|
|||
IDTE idt[256] = {0}; |
|||
|
|||
void _lidt(IDTD* idtd); |
|||
|
|||
void setup_idt(void) { |
|||
IDTD idt_descriptor = { |
|||
.size = 255 * sizeof(IDTE), |
|||
.offset = idt, |
|||
}; |
|||
|
|||
_lidt(&idt_descriptor); |
|||
} |
|||
|
|||
|
|||
static type_attr_t make_type_attr_t(uint8_t gate_type) { |
|||
|
|||
assert((gate_type & 0xf0) == 0); |
|||
|
|||
return (type_attr_t) { |
|||
.gate_type = gate_type, |
|||
.z = 0, |
|||
.dpl = 0, |
|||
.p = 1, |
|||
}; |
|||
} |
|||
|
|||
|
|||
static IDTE make_idte(void* handler, type_attr_t type_attr) { |
|||
uint64_t h = (uint64_t) handler; |
|||
|
|||
return (IDTE) { |
|||
.offset_1 = h & 0xffff, |
|||
.selector = 0x28, |
|||
.ist = 0, |
|||
.type_attr = type_attr, |
|||
.offset_2 = (h >> 16) & 0xffff, |
|||
.offset_3 = (h >> 32) & 0xffffffff, |
|||
.zero = 0, |
|||
}; |
|||
} |
|||
|
|||
static IDTE make_isr(void* handler) { |
|||
return make_idte(handler, make_type_attr_t(ATTR_64_GATE)); |
|||
} |
|||
|
|||
|
|||
void set_interrupt_handler(uint16_t number, void* handler) { |
|||
idt[number] = make_isr(handler); |
|||
} |
|||
|
|||
|
|||
void _cli(void) { |
|||
asm volatile("cli"); |
|||
} |
|||
|
|||
|
|||
void _sti(void) { |
|||
asm volatile("sti"); |
|||
} |
@ -0,0 +1,35 @@ |
|||
#ifndef IDT_H |
|||
#define IDT_H |
|||
|
|||
#include <stdint.h> |
|||
#include <stddef.h> |
|||
#include "../debug/assert.h" |
|||
|
|||
#define ATTR_64_GATE 0b1110 |
|||
#define ATTR_64_TRAP 0b1110 |
|||
|
|||
|
|||
|
|||
struct IFrame { |
|||
uint64_t RIP; |
|||
uint64_t CS; |
|||
uint64_t RFLAGS; |
|||
uint64_t RSP; |
|||
uint64_t SS; |
|||
} __packed; |
|||
|
|||
static_assert(sizeof(struct IFrame) == 40); |
|||
|
|||
|
|||
|
|||
void setup_idt(void); |
|||
|
|||
void set_interrupt_handler(uint16_t number, void* handler); |
|||
void _cli(void); |
|||
void _sti(void); |
|||
|
|||
|
|||
void setup_isr(void); |
|||
|
|||
|
|||
#endif // IDT_H
|
@ -1,7 +1,7 @@ |
|||
|
|||
[section .text] |
|||
[global _lidt] |
|||
|
|||
lidt: |
|||
lidt [rdi] |
|||
|
|||
[section .text] |
|||
[global _lidt] |
|||
|
|||
_lidt: |
|||
lidt [rdi] |
|||
ret |
@ -0,0 +1,134 @@ |
|||
#include "../klib/sprintf.h" |
|||
#include "../debug/assert.h" |
|||
#include "idt.h" |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
static void print_frame(struct IFrame* interrupt_frame) { |
|||
kprintf( |
|||
"RIP: %16lx\n" |
|||
"RSP: %16lx\n" |
|||
"CS: %16lx SS: %16lx\n" |
|||
"\n" |
|||
"RFLAGS: %8lx\n", |
|||
interrupt_frame->RIP, |
|||
interrupt_frame->RSP, |
|||
interrupt_frame->CS, |
|||
interrupt_frame->SS, |
|||
interrupt_frame->RFLAGS); |
|||
} |
|||
|
|||
|
|||
__attribute__((interrupt)) void ISR_general_handler(struct IFrame* interrupt_frame) { |
|||
(void) interrupt_frame; |
|||
kprintf("ISR_general_handler()\n"); |
|||
} |
|||
__attribute__((interrupt)) void ISR_error_handler(struct IFrame* interrupt_frame, uint64_t error_code) { |
|||
(void) interrupt_frame; |
|||
kprintf("ISR_error_handler()\n"); |
|||
} |
|||
|
|||
|
|||
__attribute__((interrupt)) void ISR_div_by_zero_handler(struct IFrame* interrupt_frame) { |
|||
kprintf("ISR_div_by_zero_handler():\n"); |
|||
print_frame(interrupt_frame); |
|||
} |
|||
|
|||
|
|||
|
|||
__attribute__((interrupt)) void ISR_debug_handler(struct IFrame* interrupt_frame) { |
|||
(void) interrupt_frame; |
|||
kprintf("ISR_debug_handler()\n"); |
|||
} |
|||
__attribute__((interrupt)) void ISR_NMI_handler(struct IFrame* interrupt_frame) { |
|||
(void) interrupt_frame; |
|||
kprintf("ISR_NMI_handler()\n"); |
|||
} |
|||
__attribute__((interrupt)) void ISR_breakpoint_handler(struct IFrame* interrupt_frame) { |
|||
(void) interrupt_frame; |
|||
kprintf("ISR_breakpoint_handler()\n"); |
|||
} |
|||
__attribute__((interrupt)) void ISR_overflow_handler(struct IFrame* interrupt_frame) { |
|||
(void) interrupt_frame; |
|||
kprintf("ISR_overflow_handler()\n"); |
|||
} |
|||
__attribute__((interrupt)) void ISR_bound_handler(struct IFrame* interrupt_frame) { |
|||
(void) interrupt_frame; |
|||
kprintf("ISR_bound_handler()\n"); |
|||
} |
|||
__attribute__((interrupt)) void ISR_invalid_opcode_handler(struct IFrame* interrupt_frame) { |
|||
(void) interrupt_frame; |
|||
kprintf("ISR_invalid_opcode_handler()\n"); |
|||
} |
|||
__attribute__((interrupt)) void ISR_device_not_available_handler(struct IFrame* interrupt_frame) { |
|||
(void) interrupt_frame; |
|||
kprintf("ISR_device_not_available_handler()\n"); |
|||
} |
|||
__attribute__((interrupt)) void ISR_double_fault_handler(struct IFrame* interrupt_frame, uint64_t error_code) { |
|||
(void) interrupt_frame; |
|||
kprintf("ISR_double_fault_handler()\n"); |
|||
} |
|||
__attribute__((interrupt)) void ISR_coproc_segment_overrun_handler(struct IFrame* interrupt_frame) { |
|||
(void) interrupt_frame; |
|||
kprintf("ISR_coproc_segment_overrun_handler()\n"); |
|||
} |
|||
__attribute__((interrupt)) void ISR_invalid_TSS_handler(struct IFrame* interrupt_frame, uint64_t error_code) { |
|||
(void) interrupt_frame; |
|||
kprintf("ISR_invalid_TSS_handler()\n"); |
|||
} |
|||
__attribute__((interrupt)) void ISR_segment_not_present_handler(struct IFrame* interrupt_frame, uint64_t error_code) { |
|||
(void) interrupt_frame; |
|||
kprintf("ISR_segment_not_present_handler()\n"); |
|||
} |
|||
__attribute__((interrupt)) void ISR_stack_segment_fault_handler(struct IFrame* interrupt_frame, uint64_t error_code) { |
|||
(void) interrupt_frame; |
|||
kprintf("ISR_stack_segment_fault_handler()\n"); |
|||
} |
|||
__attribute__((interrupt)) void ISR_general_protection_fault_handler(struct IFrame* interrupt_frame, uint64_t error_code) { |
|||
(void) interrupt_frame; |
|||
kprintf("ISR_general_protection_fault_handler()\n"); |
|||
} |
|||
__attribute__((interrupt)) void ISR_page_fault_handler(struct IFrame* interrupt_frame, uint64_t error_code) { |
|||
(void) interrupt_frame; |
|||
kprintf("ISR_page_fault_handler()\n"); |
|||
} |
|||
__attribute__((interrupt)) void ISR_spurious(struct IFrame* interrupt_frame) { |
|||
(void) interrupt_frame; |
|||
kprintf("ISR_spurious()\n"); |
|||
} |
|||
|
|||
extern uint64_t idt[256]; |
|||
|
|||
|
|||
void setup_isr(void) { |
|||
_cli(); |
|||
|
|||
set_interrupt_handler(0, (void *) ISR_div_by_zero_handler); |
|||
set_interrupt_handler(1, (void *) ISR_debug_handler); |
|||
set_interrupt_handler(2, (void *) ISR_NMI_handler); |
|||
set_interrupt_handler(3, (void *) ISR_breakpoint_handler); |
|||
set_interrupt_handler(4, (void *) ISR_overflow_handler); |
|||
set_interrupt_handler(5, (void *) ISR_bound_handler); |
|||
set_interrupt_handler(6, (void *) ISR_invalid_opcode_handler); |
|||
set_interrupt_handler(7, (void *) ISR_device_not_available_handler); |
|||
set_interrupt_handler(8, (void *) ISR_double_fault_handler); |
|||
set_interrupt_handler(9, (void *) ISR_coproc_segment_overrun_handler); |
|||
set_interrupt_handler(10, (void *) ISR_invalid_TSS_handler); |
|||
set_interrupt_handler(11, (void *) ISR_segment_not_present_handler); |
|||
set_interrupt_handler(12, (void *) ISR_stack_segment_fault_handler); |
|||
set_interrupt_handler(13, (void *) ISR_general_protection_fault_handler); |
|||
set_interrupt_handler(14, (void *) ISR_page_fault_handler); |
|||
|
|||
for(int i = 15; i <= 255; i++) |
|||
set_interrupt_handler(i, ISR_spurious); |
|||
|
|||
for(size_t i = 0; i < 16; i++) { |
|||
kprintf("entry %d:\t%16lx %16lx\n", i, idt[2*i], idt[2*i+1]); |
|||
} |
|||
|
|||
setup_idt(); |
|||
_sti(); |
|||
} |
Loading…
Reference in new issue