The files:
irq.s :
Code: Select all
.section .text
.align 4
.macro IRQ index byte
.global _irq\index
.type _irq\index, @function
_irq\index:
pushl $0
pushl $\byte
jmp isr_wrapper
.endm
.macro ISR index
.global _isr\index
.type _isr\index, @function
_isr\index:
pushl $0
pushl $\index
jmp isr_wrapper
.endm
.macro ISR_ERR index
.global _isr\index
.type _isr\index, @function
_isr\index:
pushl $\index
jmp isr_wrapper
.endm
ISR 0
ISR 1
ISR 2
ISR 3
ISR 4
ISR 5
ISR 6
ISR 7
ISR_ERR 8
ISR 9
ISR_ERR 10
ISR_ERR 11
ISR_ERR 12
ISR_ERR 13
ISR_ERR 14
ISR 15
ISR 16
ISR 17
ISR 18
ISR 19
ISR 20
ISR 21
ISR 22
ISR 23
ISR 24
ISR 25
ISR 26
ISR 27
ISR 28
ISR 29
ISR 30
ISR 31
IRQ 0, 32
IRQ 1, 33
IRQ 2, 34
IRQ 3, 35
IRQ 4, 36
IRQ 5, 37
IRQ 6, 38
IRQ 7, 39
IRQ 8, 40
IRQ 9, 41
IRQ 10, 42
IRQ 11, 43
IRQ 12, 44
IRQ 13, 45
IRQ 14, 46
IRQ 15, 47
.extern isr_handler
.type isr_handler, @function
.global isr_wrapper
isr_wrapper:
pushal
push %esp
cld
call isr_handler
add $4, %esp
popal
add $8, %esp
iretl
Code: Select all
#include <stdint.h>
#include <arch/x86/idt.h>
#include <arch/x86/regs.h>
#include <arch/x86/pic.h>
#include <sys/kprint.h>
struct InterruptDescriptor {
uint16_t offset_low; //Offset bits 0 to 15
uint16_t selector; //A code segment selector in GDT or LDT
uint8_t zero; //Just a gap, always set to zero
uint8_t type_attributes; //Gate type, DPL and present bit fields
uint16_t offset_high; //Offset bits 16 to 31
} __attribute__((packed));
struct IDTPointer{
uint16_t limit;
void* base;
} __attribute__((packed));
static struct IDTPointer idt_pointer;
struct InterruptDescriptor idt[256];
static void (*irq_handler_table[16]) (void);
void idt_set_gate(uint8_t num, void* handler, uint16_t selector, uint8_t type_attributes){
idt[num].offset_low = (uint32_t) handler & 0xFFFF;
idt[num].selector = selector;
idt[num].type_attributes = type_attributes;
idt[num].offset_high = ((uint32_t)handler >> 16) & 0xFFFF;
}
void irq_set_handler(uint8_t irq, void* handler){
irq_handler_table[irq] = handler;
}
void initialize_idt(void){
idt_pointer.limit = sizeof(idt);
idt_pointer.base = &idt;
void* isr_handlers[] = {_isr0, _isr1, _isr2, _isr3, _isr4, _isr5,
_isr6, _isr7, _isr8, _isr9, _isr10, _isr11, _isr12, _isr13, _isr14, _isr15, _isr16,
_isr17, _isr18, _isr19, _isr20, _isr21, _isr22, _isr23, _isr24, _isr25, _isr26, _isr27,
_isr28, _isr29, _isr30, _isr31};
for(int i = 0; i < 32; ++i){
idt_set_gate(i, isr_handlers[i], 0x08, 0x8E);
}
void* irq_handlers[] = {_irq0, _irq1, _irq2, _irq3, _irq4, _irq5, _irq6, _irq7, _irq8, _irq9,
_irq10, _irq11, _irq12, _irq13, _irq14, _irq15};
for(int i = 0; i < 16; ++i){
idt_set_gate(i + 32, irq_handlers[i], 0x08, 0x8E); //There are 32 entries before the first IRQ entry
}
//Load the new IDT
asm volatile ("lidt %0" :: "m"(idt_pointer));
}
static void _exception(char* message, struct x86Registers* regs){
kprintf(message);
kprintf("EAX : 0x%x EBX : 0x%x ECX : 0x%x EDX : 0x%x\n", regs->eax, regs->ebx, regs->ecx, regs->edx);
kprintf("ESP : 0x%x EBP : 0x%x ESI : 0x%x EDI : 0x%x\n", regs->esp, regs->ebp, regs->esi, regs->edi);
kprintf("EIP : 0x%x CS : 0x%x EFLAGS : 0x%x SS : 0x%x\n", regs->eip, regs->cs, regs->eflags, regs->ss);
asm volatile("hlt");
}
static void _handle_irq(struct x86Registers* regs, int irq){
irq_handler_table[irq]();
acknowledge_irq(irq);
}
struct x86Registers* isr_handler(struct x86Registers* regs){
switch (regs->interrupt_no){
case 0: _exception("Division by zero\n", regs); break;
case 3: _exception("Breakpoint\n", regs); break;
case 4: _exception("Overflow\n", regs); break;
case 5: _exception("Range exceeded\n", regs); break;
case 6: _exception("Invalid opcode\n", regs); break;
case 7: _exception("Device not available\n", regs); break;
case 8: _exception("Double fault\n", regs); break;
case 32: _handle_irq(regs, 0); break;
case 33: _handle_irq(regs, 1); break;
case 34: _handle_irq(regs, 2); break;
case 35: _handle_irq(regs, 3); break;
case 36: _handle_irq(regs, 4); break;
case 37: _handle_irq(regs, 5); break;
case 38: _handle_irq(regs, 6); break;
case 39: _handle_irq(regs, 7); break;
case 40: _handle_irq(regs, 8); break;
case 41: _handle_irq(regs, 9); break;
case 42: _handle_irq(regs, 10); break;
case 43: _handle_irq(regs, 11); break;
case 44: _handle_irq(regs, 12); break;
case 45: _handle_irq(regs, 13); break;
case 46: _handle_irq(regs, 14); break;
case 47: _handle_irq(regs, 15); break;
default: kprintf("Interrupt!"); break;
}
return regs;
}
Code: Select all
#include <stdint.h>
#include <arch/x86/ports.h>
#define PIC1_COMMAND 0x20
#define PIC1_DATA 0x21
#define PIC2_COMMAND 0xA0
#define PIC2_DATA 0xA1
void remap_pic(uint32_t offset1, uint32_t offset2){
uint8_t p1, p2;
p1 = inb(PIC1_DATA);
p2 = inb(PIC2_DATA);
outb(PIC1_COMMAND, 0x11);
iowait();
outb(PIC2_COMMAND, 0x11);
iowait();
outb(PIC1_DATA, offset1);
iowait();
outb(PIC2_DATA, offset2);
iowait();
outb(PIC1_DATA, 4);
iowait();
outb(PIC2_DATA, 2);
iowait();
outb(PIC1_DATA, 0x01);
iowait();
outb(PIC2_DATA, 0x01);
iowait();
outb(PIC1_DATA, p1);
outb(PIC2_DATA, p2);
}
void unmask_irq(uint8_t irq){
uint16_t port = PIC1_DATA;
uint8_t value;
if(irq >= 8){
port = PIC2_DATA;
irq -= 8;
}
value = inb(port) & ~(1 << irq);
outb(port, value);
}
void acknowledge_irq(uint8_t irq_no){
if (irq_no >= 8)
outb(PIC2_COMMAND, 0x20);
outb(PIC1_COMMAND, 0x20);
}
Code: Select all
#include <stdint.h>
#include <arch/x86/idt.h>
#include <arch/x86/regs.h>
#include <arch/x86/pic.h>
#include <arch/x86/ports.h>
#include <sys/kprint.h>
void pit_handler(void){
kprintf("PIT\n");
acknowledge_irq(0);
}
void initialize_pit(void) {
irq_set_handler(0, pit_handler);
unmask_irq(0);
long divisor = 1193180 / 100;
outb(0x43, 0x36);
outb(0x40, divisor & 0xFF);
outb(0x40, (divisor >> 8) & 0xFF);
}