HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Hardware interrupt handler in C++

Submitted by: @import:stackexchange-codereview··
0
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 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 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 noexcept

It'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 noexcept

For 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.