feat: add sigOnSigReturn and sigInstallTrampoline to signal
This commit is contained in:
1 parent
8f2554114f
commit
730467ce1f
1 file changed
+85
@@ -315,3 +315,88 @@ SigOutcome sigConsumePending(Thread* thread, Registers* regs, int* outSignum)
|
|||||||
newBlocked &= ~(1ull << sigStop);
|
newBlocked &= ~(1ull << sigStop);
|
||||||
thread->sigBlocked = newBlocked;
|
thread->sigBlocked = newBlocked;
|
||||||
|
|
||||||
|
/* Rewrite `regs` in place to enter the shared trampoline: rip is
|
||||||
|
the trampoline's entry, rax is the handler address its
|
||||||
|
`call *%rax` invokes, rdi is signum (the handler's sole SysV
|
||||||
|
argument). regs->rsp (the interrupted user stack) is left
|
||||||
|
untouched -- the trampoline runs on the target's own stack,
|
||||||
|
right where it already was. */
|
||||||
|
regs->rax = handler;
|
||||||
|
regs->rdi = (uint64)signum;
|
||||||
|
regs->rip = sigTrampolineVirtualAddr;
|
||||||
|
|
||||||
|
/* sigFlagSigInfo (signalnum.h): copy the SigInfo sigRaiseInfo
|
||||||
|
attached to this signum into THIS (thread, depth) pair's own
|
||||||
|
slot of the shared sigInfoVirtualAddr page -- a different slot
|
||||||
|
than any still-active outer handler's own siginfo pointer, by
|
||||||
|
the exact same depth-indexed reasoning sigSavedRegs/
|
||||||
|
sigSavedBlocked already use, so a nested sigFlagSigInfo delivery
|
||||||
|
can never clobber an outer one's still-unread copy. rdx is
|
||||||
|
always 0 (no ucontext_t this kernel can expose). Left completely
|
||||||
|
untouched otherwise -- see this function's own doc comment. */
|
||||||
|
if (thread->sigHandlerFlags[signum] & sigFlagSigInfo && sigInfoPageCount > 0) {
|
||||||
|
uint32 slot = thread->id * sigMaxNestDepth + depth;
|
||||||
|
uint32 page = slot / sigInfoSlotsPerPage;
|
||||||
|
uint32 offset = (slot % sigInfoSlotsPerPage) * (uint32)sizeof(SigInfo);
|
||||||
|
SigInfo* dst = (SigInfo*)(sigInfoFrames[page] + offset);
|
||||||
|
*dst = thread->sigPendingInfo[signum];
|
||||||
|
regs->rsi = sigInfoVirtualAddr + (uint64)page * frameSize + offset;
|
||||||
|
regs->rdx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sigOutcomeHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sigOutcomeNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sigOnSigReturn(Thread* thread, Registers* regs)
|
||||||
|
{
|
||||||
|
if (thread->sigHandlerDepth == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint32 depth = thread->sigHandlerDepth - 1;
|
||||||
|
*regs = thread->sigSavedRegs[depth];
|
||||||
|
thread->sigBlocked = thread->sigSavedBlocked[depth];
|
||||||
|
thread->sigHandlerDepth = depth;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sigInstallTrampoline(void)
|
||||||
|
{
|
||||||
|
uint64 frame = pmmAlloc();
|
||||||
|
if (frame == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint64 length = (uint64)(sigTrampolineEnd - sigTrampolineStart);
|
||||||
|
memset((void*)frame, 0, frameSize);
|
||||||
|
memcpy((void*)frame, sigTrampolineStart, length);
|
||||||
|
|
||||||
|
pagingMap(sigTrampolineVirtualAddr, frame, pagePresent | pageUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sigInstallInfoPage(void)
|
||||||
|
{
|
||||||
|
uint64 totalSlots = (uint64)threadCapacity() * sigMaxNestDepth;
|
||||||
|
uint64 pagesNeeded = (totalSlots + sigInfoSlotsPerPage - 1) / sigInfoSlotsPerPage;
|
||||||
|
if (pagesNeeded > sigInfoMaxPages)
|
||||||
|
pagesNeeded = sigInfoMaxPages;
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < pagesNeeded; i++) {
|
||||||
|
uint64 frame = pmmAlloc();
|
||||||
|
if (frame == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
memset((void*)frame, 0, frameSize);
|
||||||
|
/* pageUser, no pageWrite: a handler may only ever READ the SigInfo
|
||||||
|
it was handed a pointer to, exactly like the trampoline page
|
||||||
|
above is read+execute, never write -- the kernel is the only
|
||||||
|
writer, via `frame`'s own physical address (see the frame
|
||||||
|
comment above sigInfoFrames), never through this user-facing
|
||||||
|
mapping. */
|
||||||
|
pagingMap(sigInfoVirtualAddr + (uint64)i * frameSize, frame, pagePresent | pageUser);
|
||||||
|
sigInfoFrames[i] = frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
sigInfoPageCount = (uint32)pagesNeeded;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user