mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Fix signal delivery during context switch.
This commit is contained in:
parent
82775c4803
commit
12b5044bc7
3 changed files with 103 additions and 4 deletions
|
@ -175,6 +175,86 @@ void LoadInterruptedContext(struct interrupt_context* intctx,
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" void fake_interrupt(void);
|
||||||
|
|
||||||
|
// Pretend a particular interrupt arrived on another thread's stack. This
|
||||||
|
// assumes we're _not_ on current_thread's stack right now. This sets up the
|
||||||
|
// interrupt context such that the interrupt handler runs in that thread.
|
||||||
|
// The interrupt handler runs with premption enabled. This is used to deliver
|
||||||
|
// signals during context switches, as the signal handler needs to have
|
||||||
|
// preemption enabled.
|
||||||
|
static void FakeInterruptedContext(struct interrupt_context* intctx, int int_no)
|
||||||
|
{
|
||||||
|
#if defined(__i386__)
|
||||||
|
uintptr_t stack = current_thread->kernelstackpos +
|
||||||
|
current_thread->kernelstacksize;
|
||||||
|
stack -= sizeof(struct interrupt_context);
|
||||||
|
struct interrupt_context* fakectx = (struct interrupt_context*) stack;
|
||||||
|
memcpy(fakectx, intctx, sizeof(struct interrupt_context));
|
||||||
|
fakectx->int_no = int_no;
|
||||||
|
fakectx->err_code = 0;
|
||||||
|
stack -= 4;
|
||||||
|
stack &= 0xFFFFFFF0;
|
||||||
|
intctx->signal_pending = intctx->signal_pending;
|
||||||
|
intctx->kerrno = 0;
|
||||||
|
intctx->cr2 = 0;
|
||||||
|
intctx->ds = KDS | KRPL;
|
||||||
|
intctx->edi = intctx->edi;
|
||||||
|
intctx->esi = intctx->esi;
|
||||||
|
intctx->ebp = intctx->signal_pending;
|
||||||
|
intctx->not_esp = intctx->not_esp;
|
||||||
|
intctx->ebx = (uintptr_t) fakectx;
|
||||||
|
intctx->edx = intctx->edx;
|
||||||
|
intctx->ecx = intctx->ecx;
|
||||||
|
intctx->eax = intctx->eax;
|
||||||
|
intctx->int_no = intctx->int_no;
|
||||||
|
intctx->err_code = intctx->err_code;
|
||||||
|
intctx->eip = (uintptr_t) fake_interrupt;
|
||||||
|
intctx->cs = KCS | KRPL;
|
||||||
|
intctx->eflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
|
||||||
|
intctx->esp = stack;
|
||||||
|
intctx->ss = KDS | KRPL;
|
||||||
|
#elif defined(__x86_64__)
|
||||||
|
uintptr_t stack = current_thread->kernelstackpos +
|
||||||
|
current_thread->kernelstacksize;
|
||||||
|
stack -= sizeof(struct interrupt_context);
|
||||||
|
struct interrupt_context* fakectx = (struct interrupt_context*) stack;
|
||||||
|
memcpy(fakectx, intctx, sizeof(struct interrupt_context));
|
||||||
|
fakectx->int_no = int_no;
|
||||||
|
fakectx->err_code = 0;
|
||||||
|
stack &= 0xFFFFFFFFFFFFFFF0;
|
||||||
|
intctx->signal_pending = intctx->signal_pending;
|
||||||
|
intctx->kerrno = 0;
|
||||||
|
intctx->cr2 = 0;
|
||||||
|
intctx->ds = KDS | KRPL;
|
||||||
|
intctx->rdi = (uintptr_t) fakectx;
|
||||||
|
intctx->rsi = intctx->rsi;
|
||||||
|
intctx->rbp = intctx->signal_pending;
|
||||||
|
intctx->not_rsp = intctx->not_rsp;
|
||||||
|
intctx->rbx = (uintptr_t) fakectx;
|
||||||
|
intctx->rdx = intctx->rdx;
|
||||||
|
intctx->rcx = intctx->rcx;
|
||||||
|
intctx->rax = intctx->rax;
|
||||||
|
intctx->r8 = intctx->r8;
|
||||||
|
intctx->r9 = intctx->r9;
|
||||||
|
intctx->r10 = intctx->r10;
|
||||||
|
intctx->r11 = intctx->r11;
|
||||||
|
intctx->r12 = intctx->r12;
|
||||||
|
intctx->r13 = intctx->r13;
|
||||||
|
intctx->r14 = intctx->r14;
|
||||||
|
intctx->r15 = intctx->r15;
|
||||||
|
intctx->int_no = intctx->int_no;
|
||||||
|
intctx->err_code = intctx->err_code;
|
||||||
|
intctx->rip = (uintptr_t) fake_interrupt;
|
||||||
|
intctx->cs = KCS | KRPL;
|
||||||
|
intctx->rflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
|
||||||
|
intctx->rsp = stack;
|
||||||
|
intctx->ss = KDS | KRPL;
|
||||||
|
#else
|
||||||
|
#warning "You need to implement faking an interrupt"
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void SwitchThread(struct interrupt_context* intctx, Thread* prev, Thread* next)
|
void SwitchThread(struct interrupt_context* intctx, Thread* prev, Thread* next)
|
||||||
{
|
{
|
||||||
|
@ -237,12 +317,25 @@ static Thread* PopNextThread(bool yielded)
|
||||||
|
|
||||||
static void RealSwitch(struct interrupt_context* intctx, bool yielded)
|
static void RealSwitch(struct interrupt_context* intctx, bool yielded)
|
||||||
{
|
{
|
||||||
SwitchThread(intctx, CurrentThread(), PopNextThread(yielded));
|
Thread* old_thread = CurrentThread();
|
||||||
|
Thread* new_thread = PopNextThread(yielded);
|
||||||
|
SwitchThread(intctx, old_thread, new_thread);
|
||||||
if ( intctx->signal_pending && InUserspace(intctx) )
|
if ( intctx->signal_pending && InUserspace(intctx) )
|
||||||
{
|
{
|
||||||
Interrupt::Enable();
|
// Become the thread for real and run the signal handler.
|
||||||
Signal::DispatchHandler(intctx, NULL);
|
if ( old_thread == new_thread )
|
||||||
|
{
|
||||||
|
// We're already this thread, so run the signal handler.
|
||||||
|
Interrupt::Enable();
|
||||||
|
Signal::DispatchHandler(intctx, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We need to transfer execution to the correct stack. We know the
|
||||||
|
// the thread is in user-space and isn't using its kernel stack, and
|
||||||
|
// we know we're not using the stack right now.
|
||||||
|
FakeInterruptedContext(intctx, 130);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -388,6 +388,9 @@ interrupt_handler_prepare:
|
||||||
movq %rsp, %rdi
|
movq %rsp, %rdi
|
||||||
movq %rsp, %rbx
|
movq %rsp, %rbx
|
||||||
andq $0xFFFFFFFFFFFFFFF0, %rsp
|
andq $0xFFFFFFFFFFFFFFF0, %rsp
|
||||||
|
.global fake_interrupt
|
||||||
|
.type fake_interrupt, @function
|
||||||
|
fake_interrupt:
|
||||||
call interrupt_handler
|
call interrupt_handler
|
||||||
movq %rbx, %rsp
|
movq %rbx, %rsp
|
||||||
|
|
||||||
|
|
|
@ -385,6 +385,9 @@ fixup_relocate_stack_complete:
|
||||||
movl %esp, %ebx
|
movl %esp, %ebx
|
||||||
subl $4, %esp
|
subl $4, %esp
|
||||||
andl $0xFFFFFFF0, %esp
|
andl $0xFFFFFFF0, %esp
|
||||||
|
.global fake_interrupt
|
||||||
|
.type fake_interrupt, @function
|
||||||
|
fake_interrupt:
|
||||||
movl %ebx, (%esp)
|
movl %ebx, (%esp)
|
||||||
call interrupt_handler
|
call interrupt_handler
|
||||||
movl %ebx, %esp
|
movl %ebx, %esp
|
||||||
|
|
Loading…
Add table
Reference in a new issue