2019-05-31 08:41:28 +02:00
|
|
|
// Zig version: 0.4.0
|
|
|
|
|
2019-09-29 13:55:34 +02:00
|
|
|
const panic = @import("../../panic.zig").panic;
|
2019-05-31 08:41:28 +02:00
|
|
|
const idt = @import("idt.zig");
|
|
|
|
const arch = @import("arch.zig");
|
2019-06-02 18:14:02 +02:00
|
|
|
const pic = @import("pic.zig");
|
2019-05-31 08:41:28 +02:00
|
|
|
|
|
|
|
const NUMBER_OF_ENTRIES: u16 = 16;
|
|
|
|
|
|
|
|
const IRQ_OFFSET: u16 = 32;
|
|
|
|
|
2019-06-02 18:14:02 +02:00
|
|
|
// The external assembly that is fist called to set up the interrupt handler.
|
2019-05-31 08:41:28 +02:00
|
|
|
extern fn irq0() void;
|
|
|
|
extern fn irq1() void;
|
|
|
|
extern fn irq2() void;
|
|
|
|
extern fn irq3() void;
|
|
|
|
extern fn irq4() void;
|
|
|
|
extern fn irq5() void;
|
|
|
|
extern fn irq6() void;
|
|
|
|
extern fn irq7() void;
|
|
|
|
extern fn irq8() void;
|
|
|
|
extern fn irq9() void;
|
|
|
|
extern fn irq10() void;
|
|
|
|
extern fn irq11() void;
|
|
|
|
extern fn irq12() void;
|
|
|
|
extern fn irq13() void;
|
|
|
|
extern fn irq14() void;
|
|
|
|
extern fn irq15() void;
|
|
|
|
|
2019-06-02 18:14:02 +02:00
|
|
|
/// The list of IRQ handlers initialised to unhandled.
|
2019-09-03 20:13:26 +02:00
|
|
|
var irq_handlers: [NUMBER_OF_ENTRIES]fn (*arch.InterruptContext) void = [_]fn (*arch.InterruptContext) void{unhandled} ** NUMBER_OF_ENTRIES;
|
2019-05-31 08:41:28 +02:00
|
|
|
|
2019-06-02 18:14:02 +02:00
|
|
|
///
|
|
|
|
/// A dummy handler that will make a call to panic as it is a unhandled interrupt.
|
|
|
|
///
|
|
|
|
/// Arguments:
|
|
|
|
/// IN context: *arch.InterruptContext - Pointer to the interrupt context containing the
|
|
|
|
/// contents of the register at the time of the interrupt.
|
|
|
|
///
|
2019-05-31 08:41:28 +02:00
|
|
|
fn unhandled(context: *arch.InterruptContext) void {
|
|
|
|
const interrupt_num: u8 = @truncate(u8, context.int_num - IRQ_OFFSET);
|
2019-09-29 13:55:34 +02:00
|
|
|
panic(null, "Unhandled IRQ number {}", interrupt_num);
|
2019-05-31 08:41:28 +02:00
|
|
|
}
|
|
|
|
|
2019-06-02 18:14:02 +02:00
|
|
|
///
|
|
|
|
/// The IRQ handler that each of the IRQ's will call when a interrupt happens.
|
|
|
|
///
|
|
|
|
/// Arguments:
|
|
|
|
/// IN context: *arch.InterruptContext - Pointer to the interrupt context containing the
|
|
|
|
/// contents of the register at the time of the interrupt.
|
|
|
|
///
|
2019-05-31 08:41:28 +02:00
|
|
|
export fn irqHandler(context: *arch.InterruptContext) void {
|
|
|
|
const irq_num: u8 = @truncate(u8, context.int_num - IRQ_OFFSET);
|
|
|
|
// Make sure it isn't a spurious irq
|
2019-06-02 18:14:02 +02:00
|
|
|
if (!pic.spuriousIrq(irq_num)) {
|
2019-05-31 08:41:28 +02:00
|
|
|
irq_handlers[irq_num](context);
|
|
|
|
// Send the end of interrupt command
|
2019-06-02 18:14:02 +02:00
|
|
|
pic.sendEndOfInterrupt(irq_num);
|
2019-05-31 08:41:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-17 19:24:27 +02:00
|
|
|
///
|
|
|
|
/// Open an IDT entry with index and handler. This will also handle the errors.
|
|
|
|
///
|
|
|
|
/// Arguments:
|
|
|
|
/// IN index: u8 - The IDT interrupt number.
|
|
|
|
/// IN handler: idt.InterruptHandler - The IDT handler.
|
|
|
|
///
|
|
|
|
fn openIrq(index: u8, handler: idt.InterruptHandler) void {
|
|
|
|
idt.openInterruptGate(index, handler) catch |err| switch (err) {
|
|
|
|
error.IdtEntryExists => {
|
2019-09-29 13:55:34 +02:00
|
|
|
panic(@errorReturnTrace(), "Error opening IRQ number: {} exists", index);
|
2019-09-17 19:24:27 +02:00
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2019-06-02 18:14:02 +02:00
|
|
|
///
|
|
|
|
/// Register a IRQ by setting its interrupt handler to the given function. This will also clear the
|
|
|
|
/// mask bit in the PIC so interrupts can happen.
|
|
|
|
///
|
|
|
|
/// Arguments:
|
2019-10-01 18:59:42 +02:00
|
|
|
/// IN irq_num: u8 - The IRQ number to register.
|
2019-06-02 18:14:02 +02:00
|
|
|
///
|
2019-10-01 18:59:42 +02:00
|
|
|
pub fn registerIrq(irq_num: u8, handler: fn (*arch.InterruptContext) void) void {
|
2019-05-31 08:41:28 +02:00
|
|
|
irq_handlers[irq_num] = handler;
|
2019-06-02 18:14:02 +02:00
|
|
|
pic.clearMask(irq_num);
|
2019-05-31 08:41:28 +02:00
|
|
|
}
|
|
|
|
|
2019-06-02 18:14:02 +02:00
|
|
|
///
|
|
|
|
/// Unregister a IRQ by setting its interrupt handler to the unhandled function call to panic. This
|
|
|
|
/// will also set the mask bit in the PIC so no interrupts can happen anyway.
|
|
|
|
///
|
|
|
|
/// Arguments:
|
|
|
|
/// IN irq_num: u16 - The IRQ number to unregister.
|
|
|
|
///
|
2019-05-31 08:41:28 +02:00
|
|
|
pub fn unregisterIrq(irq_num: u16) void {
|
|
|
|
irq_handlers[irq_num] = unhandled;
|
2019-06-02 18:14:02 +02:00
|
|
|
pic.setMask(irq_num);
|
2019-05-31 08:41:28 +02:00
|
|
|
}
|
|
|
|
|
2019-06-02 18:14:02 +02:00
|
|
|
///
|
|
|
|
/// Initialise the IRQ interrupts by first remapping the port addresses and then opening up all
|
|
|
|
/// the IDT interrupt gates for each IRQ.
|
|
|
|
///
|
2019-05-31 08:41:28 +02:00
|
|
|
pub fn init() void {
|
|
|
|
// Open all the IRQ's
|
2019-09-17 19:24:27 +02:00
|
|
|
openIrq(32, irq0);
|
|
|
|
openIrq(33, irq1);
|
|
|
|
openIrq(34, irq2);
|
|
|
|
openIrq(35, irq3);
|
|
|
|
openIrq(36, irq4);
|
|
|
|
openIrq(37, irq5);
|
|
|
|
openIrq(38, irq6);
|
|
|
|
openIrq(39, irq7);
|
|
|
|
openIrq(40, irq8);
|
|
|
|
openIrq(41, irq9);
|
|
|
|
openIrq(42, irq10);
|
|
|
|
openIrq(43, irq11);
|
|
|
|
openIrq(44, irq12);
|
|
|
|
openIrq(45, irq13);
|
|
|
|
openIrq(46, irq14);
|
|
|
|
openIrq(47, irq15);
|
2019-09-03 20:13:26 +02:00
|
|
|
}
|