add interrupts (not yet fully working)

This commit is contained in:
trimill 2024-01-29 16:25:39 -05:00
parent e57c64c0e9
commit 5726080194
No known key found for this signature in database
GPG key ID: 4F77A16E17E10BCB
5 changed files with 216 additions and 3 deletions

View file

@ -117,7 +117,6 @@ start:
;push ebx ; Call our function to set up basic paging ;push ebx ; Call our function to set up basic paging
;call amd64_shim ;call amd64_shim
mov eax, cr4 ; Enable the PAE bit mov eax, cr4 ; Enable the PAE bit
or eax, 1 << 5 or eax, 1 << 5
mov cr4, eax mov cr4, eax
@ -139,6 +138,7 @@ code64:
pop rdi pop rdi
call amd64_shim call amd64_shim
mov rdi, rax mov rdi, rax
sti
call kmain call kmain
cli cli
halt: halt:

92
src/arch/amd64/idt.S Normal file
View file

@ -0,0 +1,92 @@
extern idt_exception_handler
global isr_stub_table
; call the exception handler with the interrupt number
; args: interrupt number
%macro ISRException 1
align 8
isr_stub_%+%1:
cld
mov rdi, %1
mov rsi, 0
call idt_exception_handler
iretq
%endmacro
; call the exception handler with the interrupt number
; these exceptions also put an error code on the stack
; args: interrupt number
%macro ISRExceptionCode 1
align 8
isr_stub_%+%1:
cld
mov rdi, %1
pop rsi
call idt_exception_handler
iretq
%endmacro
; do nothing
; args: interrupt number
%macro ISRIgnore 1
align 8
isr_stub_%+%1:
iretq
%endmacro
; isr stubs
section .text
bits 64
ISRException 0
ISRException 1
ISRException 2
ISRException 3
ISRException 4
ISRException 5
ISRException 6
ISRException 7
ISRExceptionCode 8
ISRException 9
ISRExceptionCode 10
ISRExceptionCode 11
ISRExceptionCode 12
ISRExceptionCode 13
ISRExceptionCode 14
ISRException 15
ISRException 16
ISRExceptionCode 17
ISRException 18
ISRException 19
ISRException 20
ISRExceptionCode 21
ISRException 22
ISRException 23
ISRException 24
ISRException 25
ISRException 26
ISRException 27
ISRException 28
ISRExceptionCode 29
ISRExceptionCode 30
ISRException 31
%assign i 32
; ignore other interrupts
%rep 0x100 - i
ISRIgnore i
%assign i i+1
%endrep
; isr stub table
section .rodata
bits 64
align 16
isr_stub_table:
%assign i 0
%rep 256
dq isr_stub_%+i
%assign i i+1
%endrep

118
src/arch/amd64/idt.c Normal file
View file

@ -0,0 +1,118 @@
#include <stdint.h>
#include <stddef.h>
#include <panic.h>
#include <lib.h>
#include <serial.h>
#include "idt.h"
#define IDT_SIZE 256
struct idt_entry {
uint16_t isr_low; // low 16 bits of isr
uint16_t kernel_cs; // kernel segment selector
uint8_t ist; // interrupt stack table
uint8_t flags; // gate type, privilege level, present bit
uint16_t isr_mid; // middle 16 bits of isr
uint32_t isr_high; // high 32 bits of isr
uint32_t reserved;
} __attribute__((packed));
struct idtr {
uint16_t size;
void *address;
} __attribute__((packed));
// interrupt gate
#define GATE_64BIT_INT 0x0E
// trap gate
#define GATE_64BIT_TRAP 0x0F
// privilege ring allowed to call interrupt
#define RING0 0x00
#define RING1 0x20
#define RING2 0x40
#define RING3 0x60
// interrupt is present in IDT
#define PRESENT 0x80
__attribute__((aligned(0x10)))
static struct idt_entry idt[256];
static struct idtr idtr;
// from idt.S
extern void *isr_stub_table[];
// initialize and load the IDT
void idt_init(void) {
// initialize idtr
idtr.address = &idt;
idtr.size = (uint16_t)sizeof(struct idt_entry) * IDT_SIZE - 1;
// initialize idt
for(size_t vector = 0; vector < IDT_SIZE; vector++) {
struct idt_entry* entry = &idt[vector];
uint64_t isr = (uint64_t)isr_stub_table[vector];
// interrupts before 0x20 are for cpu exceptions
uint8_t gate_type = (vector < 0x20) ? GATE_64BIT_TRAP : GATE_64BIT_INT;
entry->kernel_cs = 0x08; // offset of 1 into GDT
entry->ist = 0;
entry->flags = PRESENT | RING0 | gate_type;
entry->isr_low = isr & 0xffff;
entry->isr_mid = (isr >> 16) & 0xffff;
entry->isr_high = isr >> 32;
entry->reserved = 0;
}
__asm__ volatile ("lidt %0" : : "m"(idtr));
}
// Intel manual vol 3 ch 6.3.1
char *EXCEPTIONS[] = {
"Exception 0x00 Divide Error",
"Exception 0x01 Debug Exception",
"Exception 0x02 NMI Interrupt",
"Exception 0x03 Breakpoint",
"Exception 0x04 Overflow",
"Exception 0x05 BOUND Range Exceeded",
"Exception 0x06 Invalid Opcode",
"Exception 0x07 Device Not Available",
"Exception 0x08 Double Fault",
"Exception 0x09 Coprocessor Segment Overrun",
"Exception 0x0A Invalid TSS",
"Exception 0x0B Segment Not Present",
"Exception 0x0C Stack-Segment Fault",
"Exception 0x0D General Protection",
"Exception 0x0E Page Fault",
"Exception 0x0F Reserved",
"Exception 0x10 x87 FPU Floating-Point Error",
"Exception 0x11 Alignment Check",
"Exception 0x12 Machine Check",
"Exception 0x13 SIMD Floaing-Point Exception",
"Exception 0x14 Virtualization Exception",
"Exception 0x15 Control Protection Exception",
"Exception 0x16 Reserved",
"Exception 0x17 Reserved",
"Exception 0x18 Reserved",
"Exception 0x19 Reserved",
"Exception 0x1A Reserved",
"Exception 0x1B Reserved",
"Exception 0x1C Reserved",
"Exception 0x1D Reserved",
"Exception 0x1E Reserved",
"Exception 0x1F Reserved",
};
void idt_exception_handler(uint64_t exception, uint64_t code) {
// TODO don't just panic
char buf[80];
char *end = strcpy(buf, EXCEPTIONS[exception]);
end = strcpy(end, "\nError code 0x");
ltoa(code, end, 16);
panic(buf);
}

3
src/arch/amd64/idt.h Normal file
View file

@ -0,0 +1,3 @@
#pragma once
void idt_init();

View file

@ -6,13 +6,13 @@
#include "paging.h" #include "paging.h"
#include "mboot.h" #include "mboot.h"
#include "idt.h"
static struct boot_info boot_info; static struct boot_info boot_info;
// entry point for amd64
void* amd64_shim(void *mboot_data_ptr) { void* amd64_shim(void *mboot_data_ptr) {
serial_init(); serial_init();
paging_init(); paging_init();
idt_init();
kmap_page(mboot_data_ptr, mboot_data_ptr, F_WRITEABLE); kmap_page(mboot_data_ptr, mboot_data_ptr, F_WRITEABLE);