Here's my context structure:
Code: Select all
#pragma pack (push, 1)
struct context64 {
std::uint64_t gs;
std::uint64_t fs;
std::uint64_t r15;
std::uint64_t r14;
std::uint64_t r13;
std::uint64_t r12;
std::uint64_t r11;
std::uint64_t r10;
std::uint64_t r9;
std::uint64_t r8;
std::uint64_t rbp;
std::uint64_t rsi;
std::uint64_t rdi;
std::uint64_t rdx;
std::uint64_t rcx;
std::uint64_t rbx;
std::uint64_t rax;
std::uint64_t int_no;
std::uint64_t error;
std::uint64_t rip;
std::uint64_t cs;
std::uint64_t rflags;
std::uint64_t rsp;
std::uint64_t ss;
};
#pragma pack(pop)
Code: Select all
#define PUSHA \
push %rax; \
push %rbx; \
push %rcx; \
push %rdx; \
push %rdi; \
push %rsi; \
push %rbp; \
push %r8; \
push %r9; \
push %r10; \
push %r11; \
push %r12; \
push %r13; \
push %r14; \
push %r15
#define POPA \
pop %r15; \
pop %r14; \
pop %r13; \
pop %r12; \
pop %r11; \
pop %r10; \
pop %r9; \
pop %r8; \
pop %rbp; \
pop %rsi; \
pop %rdi; \
pop %rdx; \
pop %rcx; \
pop %rbx; \
pop %rax
#define irq(n) \
.align 16; \
.globl _irq##n; \
_irq##n: \
push $-1; \
push $0x##n; \
jmp _interrupt_stub;
_interrupt_stub:
PUSHA
push %fs
push %gs
/* make sure we have a sane kernel segment setup */
xor %ax, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
movq %rsp, %rdi
call _interrupt_handler
movq %rax, %rsp
pop %gs
pop %fs
POPA
addq $16, %rsp
iretq
irq(00)
Finally, my handler looks something like this (assume runqueue has same functionality as std::list in c++)
Code: Select all
void* _interrupt_handler(void *p) {
// get a context to look at..
context64 *ctx = reinterpret_cast<context64 *>(p);
// if it's hardware IRQ, send an EOI
if(ctx->int_no < 16) {
pic::send_eoi(ctx->int_no);
}
// timer interrupt, possible task swap?
if(ctx->int_no == 0) {
// if this isn't the very first task swap, store the current stack pointer into the current running task
if(current) {
current->m_KernelStackAddress = p;
runqueue.push_back(current);
}
current = runqueue.front();
runqueue.pop_front();
return current->m_KernelStackAddress;
}
return p;
}
Thanks