patterncppMinor
Hardware interrupt handler in C++
Viewed 0 times
handlerinterrupthardware
Problem
I wrote this class to use a C++ function as hardware interrupt handler. The idea is to have a single entry point where I can switch stacks, and call a chain of
It works... but I think it's a pretty ugly hack. Is there anything I could improve here?
```
class __attribute__((packed)) interrupt_wrapper
{
using function_ptr = void(*)(unsigned);
unsigned int_vector; // [eax-0x1C]
selector ds; // [eax-0x18]
selector es; // [eax-0x16]
selector fs; // [eax-0x14]
selector gs; // [eax-0x12]
function_ptr entry_point; // [eax-0x10]
std::array code; // [eax-0x0C]
public:
interrupt_wrapper(unsigned vec, function_ptr f) : int_vector(vec), entry_point(f)
{
byte* start;
std::size_t size;
asm volatile (
".intel_syntax noprefix;"
"jmp interrupt_wrapper_end%=;"
// --- \/\/\/\/\/\/ --- //
"interrupt_wrapper_begin%=:;" // On entry, the only known register is CS.
"push ds; push es; push fs; push gs; pusha;" // 7 bytes
"call get_eip%=;" // call near/relative (E8) // 5 bytes
"get_eip%=: pop eax;" // Pop EIP into EAX and use it to find our variables
"mov ds, cs:[eax-0x18];" // Restore segment registers
"mov es, cs:[eax-0x16];"
"mov fs, cs:[eax-0x14];"
"mov gs, cs:[eax-0x12];"
"push cs:[eax-0x1C];" // Pass our interrupt number along
"call cs:[eax-0x10];" // Call the entry point
"add esp, 4;"
"popa; pop gs; pop fs; pop es; pop ds;"
"sti;" // IRET is not guaranteed to set the interrupt flag.
"iret;"
"interrupt_wrapper_end%=:;"
// --- /\/\/\/\/\/\ --- //
"mov %0, offset inter
std::function objects to handle the interrupt.It works... but I think it's a pretty ugly hack. Is there anything I could improve here?
```
class __attribute__((packed)) interrupt_wrapper
{
using function_ptr = void(*)(unsigned);
unsigned int_vector; // [eax-0x1C]
selector ds; // [eax-0x18]
selector es; // [eax-0x16]
selector fs; // [eax-0x14]
selector gs; // [eax-0x12]
function_ptr entry_point; // [eax-0x10]
std::array code; // [eax-0x0C]
public:
interrupt_wrapper(unsigned vec, function_ptr f) : int_vector(vec), entry_point(f)
{
byte* start;
std::size_t size;
asm volatile (
".intel_syntax noprefix;"
"jmp interrupt_wrapper_end%=;"
// --- \/\/\/\/\/\/ --- //
"interrupt_wrapper_begin%=:;" // On entry, the only known register is CS.
"push ds; push es; push fs; push gs; pusha;" // 7 bytes
"call get_eip%=;" // call near/relative (E8) // 5 bytes
"get_eip%=: pop eax;" // Pop EIP into EAX and use it to find our variables
"mov ds, cs:[eax-0x18];" // Restore segment registers
"mov es, cs:[eax-0x16];"
"mov fs, cs:[eax-0x14];"
"mov gs, cs:[eax-0x12];"
"push cs:[eax-0x1C];" // Pass our interrupt number along
"call cs:[eax-0x10];" // Call the entry point
"add esp, 4;"
"popa; pop gs; pop fs; pop es; pop ds;"
"sti;" // IRET is not guaranteed to set the interrupt flag.
"iret;"
"interrupt_wrapper_end%=:;"
// --- /\/\/\/\/\/\ --- //
"mov %0, offset inter
Solution
We're missing some pieces, such as the
Make the constructor
It's unlikely that an exception within the constructor would be a welcome event. For that reason, your constructor should be declared
Make
For similar reasons, I'd suggest making
Be careful with interrupt flags
Instead of disabling all interrupts using
memory_descriptor and far_ptr32 classes and get_cs function and I guessed at the definitions of selector and byte, but with that said, here's what I found that may help you improve your code.Make the constructor
noexceptIt's unlikely that an exception within the constructor would be a welcome event. For that reason, your constructor should be declared
noexcept.Make
function_ptr noexceptFor similar reasons, I'd suggest making
function_ptr also noexcept:using function_ptr = void(*)(unsigned) noexcept;Be careful with interrupt flags
Instead of disabling all interrupts using
sti, it might be better to restore the interrupt flag to whatever it had been. Although the interrupt could not have been called by hardware if the interrupt flag had been reset (that is, interrupts disabled) but it's not uncommon to chain interrupts by having one hardware interrupt chain to another via explicit call. In that circumstance, the hardware flag should not be re-enabled lest the interrupt chain be incorrectly interrupted.Code Snippets
using function_ptr = void(*)(unsigned) noexcept;Context
StackExchange Code Review Q#122412, answer score: 2
Revisions (0)
No revisions yet.