154 lines
6.2 KiB
C
154 lines
6.2 KiB
C
// Trap-frame tracking. This file owns current-thread trap snapshots and validation for user diagnostics.
|
|
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
#include <kernel/ke_trap.h>
|
|
#include <kernel/ke_thread.h>
|
|
#include <kernel/ke_sched.h>
|
|
#include <kernel/ke_debug.h>
|
|
#include <kernel/ke_apc.h>
|
|
|
|
#define STATIC_ASSERT_OFFSET(type, field, expected) \
|
|
_Static_assert(offsetof(type, field) == (expected), \
|
|
#type "." #field " offset must match assembly")
|
|
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, Magic, 0);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, Kind, 8);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, Vector, 12);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, PreviousMode, 16);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, Rax, 24);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, Rcx, 32);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, Rdx, 40);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, Rbx, 48);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, Rbp, 56);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, Rsi, 64);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, Rdi, 72);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, R8, 80);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, R9, 88);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, R10, 96);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, R11, 104);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, R12, 112);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, R13, 120);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, R14, 128);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, R15, 136);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, Rip, 144);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, Cs, 152);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, Rflags, 160);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, Rsp, 168);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, Ss, 176);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, RipSlot, 184);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, CsSlot, 192);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, RflagsSlot, 200);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, RspSlot, 208);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, SsSlot, 216);
|
|
STATIC_ASSERT_OFFSET(KTRAP_FRAME, PreviousFrame, 224);
|
|
_Static_assert(sizeof(KTRAP_FRAME) == 240, "KTRAP_FRAME size must match ke_syscall.asm");
|
|
|
|
// Implements the trap Frame From User operation.
|
|
bool KeTrapFrameFromUser(const KTRAP_FRAME* frame) {
|
|
if (!frame || frame->Magic != KTRAP_FRAME_MAGIC) return false;
|
|
return (frame->Cs & 3u) == 3u;
|
|
}
|
|
|
|
// Returns current Trap Frame.
|
|
KTRAP_FRAME* KeGetCurrentTrapFrame(void) {
|
|
THREAD* t = KeGetCurrentThread();
|
|
if (!t) return (KTRAP_FRAME*)0;
|
|
return t->TrapFrame;
|
|
}
|
|
|
|
// Implements the enter Trap Frame operation.
|
|
void KiEnterTrapFrame(KTRAP_FRAME* frame) {
|
|
if (!frame || frame->Magic != KTRAP_FRAME_MAGIC)
|
|
KePanic(KE_PANIC_CODE_TRAP, "KiEnterTrapFrame: invalid trap frame 0x%016llX\n", (uint64_t)frame);
|
|
|
|
THREAD* t = KeGetCurrentThread();
|
|
if (!t) return;
|
|
|
|
frame->PreviousMode = KeTrapFrameFromUser(frame) ? KTRAP_MODE_USER : KTRAP_MODE_KERNEL;
|
|
frame->PreviousFrame = t->TrapFrame;
|
|
t->TrapFrame = frame;
|
|
}
|
|
|
|
// Implements the exit Trap Frame operation.
|
|
void KiExitTrapFrame(KTRAP_FRAME* frame) {
|
|
if (!frame || frame->Magic != KTRAP_FRAME_MAGIC)
|
|
KePanic(KE_PANIC_CODE_TRAP, "KiExitTrapFrame: invalid trap frame 0x%016llX\n", (uint64_t)frame);
|
|
|
|
// Give eligible user APCs a chance to redirect through the registered
|
|
// dispatcher before committing IRET slots. Interrupt APCs are eligible on
|
|
// any user return; ordinary APCs still require an alertable wait.
|
|
KiCheckForUserApcDelivery(frame);
|
|
|
|
// Commit editable return state. Kernel-mode interrupts have no RSP/SS
|
|
// hardware slots, so those pointers are NULL in that case.
|
|
if (frame->RipSlot) *frame->RipSlot = frame->Rip;
|
|
if (frame->CsSlot) *frame->CsSlot = frame->Cs;
|
|
if (frame->RflagsSlot) *frame->RflagsSlot = frame->Rflags;
|
|
if (frame->RspSlot) *frame->RspSlot = frame->Rsp;
|
|
if (frame->SsSlot) *frame->SsSlot = frame->Ss;
|
|
|
|
THREAD* t = KeGetCurrentThread();
|
|
if (t) {
|
|
if (t->TrapFrame != frame)
|
|
KePanic(KE_PANIC_CODE_TRAP, "KiExitTrapFrame: trap-frame stack mismatch top=0x%016llX frame=0x%016llX\n",
|
|
(uint64_t)t->TrapFrame, (uint64_t)frame);
|
|
t->TrapFrame = frame->PreviousFrame;
|
|
}
|
|
}
|
|
|
|
void KiValidateSyscallTrapFrame(uint64_t nr, uint64_t a0, uint64_t a1,
|
|
uint64_t a2, uint64_t a3) {
|
|
KTRAP_FRAME* f = KeGetCurrentTrapFrame();
|
|
if (!f)
|
|
KePanic(KE_PANIC_CODE_TRAP, "syscall trap validation: no current trap frame for nr=%llu\n", nr);
|
|
if (f->Magic != KTRAP_FRAME_MAGIC)
|
|
KePanic(KE_PANIC_CODE_TRAP, "syscall trap validation: bad magic 0x%016llX\n", f->Magic);
|
|
if (f->Kind != KTRAP_KIND_SYSCALL)
|
|
KePanic(KE_PANIC_CODE_TRAP, "syscall trap validation: kind=%u, expected syscall\n", f->Kind);
|
|
if (!KeTrapFrameFromUser(f) || f->PreviousMode != KTRAP_MODE_USER)
|
|
KePanic(KE_PANIC_CODE_TRAP, "syscall trap validation: syscall did not come from user cs=0x%016llX mode=%u\n",
|
|
f->Cs, f->PreviousMode);
|
|
if (f->Rax != nr || f->Rcx != a0 || f->Rdx != a1 || f->R8 != a2 ||
|
|
f->R9 != a3) {
|
|
KePanic(KE_PANIC_CODE_TRAP, "syscall trap validation: arg mismatch nr=%llu tf=%llu/%llX/%llX/%llX/%llX call=%llu/%llX/%llX/%llX/%llX\n",
|
|
nr, f->Rax, f->Rcx, f->Rdx, f->R8, f->R9,
|
|
nr, a0, a1, a2, a3);
|
|
}
|
|
}
|
|
|
|
// Returns current Trap Frame.
|
|
KSTATUS KeQueryCurrentTrapFrame(SYS_TRAP_FRAME_INFO_K* out) {
|
|
if (!out) return NTLSTATUS_INVALID_PARAMETER;
|
|
|
|
KTRAP_FRAME* f = KeGetCurrentTrapFrame();
|
|
if (!f || f->Magic != KTRAP_FRAME_MAGIC)
|
|
return NTLSTATUS_FAILURE;
|
|
|
|
uint32_t size = out->Size;
|
|
if (size < sizeof(SYS_TRAP_FRAME_INFO_K)) {
|
|
out->Size = sizeof(SYS_TRAP_FRAME_INFO_K);
|
|
return NTLSTATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
memset(out, 0, sizeof(*out));
|
|
out->Size = sizeof(*out);
|
|
out->Kind = f->Kind;
|
|
out->Vector = f->Vector;
|
|
out->PreviousMode = f->PreviousMode;
|
|
out->Rip = f->Rip;
|
|
out->Cs = f->Cs;
|
|
out->Rflags = f->Rflags;
|
|
out->Rsp = f->Rsp;
|
|
out->Ss = f->Ss;
|
|
out->Rax = f->Rax;
|
|
out->Rcx = f->Rcx;
|
|
out->Rdx = f->Rdx;
|
|
out->R8 = f->R8;
|
|
out->R9 = f->R9;
|
|
out->R10 = f->R10;
|
|
out->R11 = f->R11;
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|