Skip to content
Snippets Groups Projects
Commit 9120291b authored by Avi Kivity's avatar Avi Kivity
Browse files

interrupts: add support for registering interrupt handlers

parent c1a44fef
No related branches found
No related tags found
No related merge requests found
...@@ -79,3 +79,16 @@ exception_noerror_entry ex_mf, math_fault ...@@ -79,3 +79,16 @@ exception_noerror_entry ex_mf, math_fault
exception_error_entry ex_ac, alignment_check exception_error_entry ex_ac, alignment_check
exception_noerror_entry ex_mc, machine_check exception_noerror_entry ex_mc, machine_check
exception_noerror_entry ex_xm, simd_exception exception_noerror_entry ex_xm, simd_exception
.align 16
.global interrupt_entry
interrupt_entry:
vector = 32
.rept 256 - 32
.align 16
pushq $vector
jmp interrupt_entry_common
vector = vector + 1
.endr
exception_error_entry interrupt_entry_common, interrupt
#include "exceptions.hh" #include "exceptions.hh"
#include "mmu.hh" #include "mmu.hh"
#include "processor.hh" #include "processor.hh"
#include "interrupt.hh"
#include <boost/format.hpp>
#include "debug.hh"
typedef boost::format fmt;
interrupt_descriptor_table idt; interrupt_descriptor_table idt;
...@@ -47,6 +52,11 @@ interrupt_descriptor_table::interrupt_descriptor_table() ...@@ -47,6 +52,11 @@ interrupt_descriptor_table::interrupt_descriptor_table()
add_entry(17, ex_ac); add_entry(17, ex_ac);
add_entry(18, ex_mc); add_entry(18, ex_mc);
add_entry(19, ex_xm); add_entry(19, ex_xm);
extern char interrupt_entry[];
for (unsigned i = 32; i < 256; ++i) {
add_entry(i, reinterpret_cast<void (*)()>(interrupt_entry + (i - 32) * 16));
}
} }
void interrupt_descriptor_table::add_entry(unsigned vec, void (*handler)()) void interrupt_descriptor_table::add_entry(unsigned vec, void (*handler)())
...@@ -72,6 +82,57 @@ interrupt_descriptor_table::load_on_cpu() ...@@ -72,6 +82,57 @@ interrupt_descriptor_table::load_on_cpu()
reinterpret_cast<ulong>(&_idt)); reinterpret_cast<ulong>(&_idt));
processor::lidt(d); processor::lidt(d);
} }
unsigned interrupt_descriptor_table::register_handler(std::function<void ()> handler)
{
for (unsigned i = 32; i < 256; ++i) {
if (!_handlers[i]) {
_handlers[i] = handler;
return i;
}
}
abort();
}
void interrupt_descriptor_table::unregister_handler(unsigned vector)
{
_handlers[vector] = std::function<void ()>();
}
void interrupt_descriptor_table::invoke_interrupt(unsigned vector)
{
_handlers[vector]();
}
extern "C" { void interrupt(exception_frame* frame); }
void interrupt(exception_frame* frame)
{
unsigned vector = frame->error_code;
debug(fmt("interrupt %x") % vector);
idt.invoke_interrupt(vector);
processor::wrmsr(0x80b, 0); // EOI
}
msi_interrupt_handler::msi_interrupt_handler(std::function<void ()> handler)
: _vector(idt.register_handler(handler))
, _handler(handler)
{
}
msi_interrupt_handler::~msi_interrupt_handler()
{
idt.unregister_handler(_vector);
}
msi_message msi_interrupt_handler::config()
{
msi_message ret;
ret.addr = 0xfee00000;
ret.data = 0x4000 | _vector;
return ret;
}
#define DUMMY_HANDLER(x) \ #define DUMMY_HANDLER(x) \
extern "C" void x(); void x() { abort(); } extern "C" void x(); void x() { abort(); }
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#define EXCEPTIONS_HH #define EXCEPTIONS_HH
#include <stdint.h> #include <stdint.h>
#include <functional>
struct exception_frame { struct exception_frame {
typedef unsigned long ulong; typedef unsigned long ulong;
...@@ -33,6 +34,9 @@ class interrupt_descriptor_table { ...@@ -33,6 +34,9 @@ class interrupt_descriptor_table {
public: public:
interrupt_descriptor_table(); interrupt_descriptor_table();
void load_on_cpu(); void load_on_cpu();
unsigned register_handler(std::function<void ()> handler);
void unregister_handler(unsigned vector);
void invoke_interrupt(unsigned vector);
private: private:
typedef uint8_t u8; typedef uint8_t u8;
typedef uint16_t u16; typedef uint16_t u16;
...@@ -59,6 +63,7 @@ private: ...@@ -59,6 +63,7 @@ private:
} __attribute__((aligned(16))); } __attribute__((aligned(16)));
void add_entry(unsigned vec, void (*handler)()); void add_entry(unsigned vec, void (*handler)());
idt_entry _idt[256]; idt_entry _idt[256];
std::function<void ()> _handlers[256];
}; };
extern interrupt_descriptor_table idt; extern interrupt_descriptor_table idt;
......
#ifndef INTERRUPT_HH_
#define INTERRUPT_HH_
#include <functional>
#include "types.hh"
struct msi_message {
u64 addr;
u32 data;
};
class msi_interrupt_handler {
public:
explicit msi_interrupt_handler(std::function<void ()> handler);
~msi_interrupt_handler();
msi_message config();
private:
unsigned _vector;
std::function<void ()> _handler;
};
#endif /* INTERRUPT_HH_ */
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment