mirror of
https://github.com/zer0condition/GoodmansKernel/
synced 2026-08-19 01:14:35 +00:00
96 lines
2.8 KiB
C
96 lines
2.8 KiB
C
/* log_ring.c - kernel-side ring of recent debug lines. GUI polls via ioctl. */
|
|
#include "inc/gvm.h"
|
|
#include "../shared/goodmans_ioctl.h"
|
|
|
|
static gvm_log_entry g_ring[GVM_LOG_ENTRIES];
|
|
static ULONG64 g_seq = 0; // strictly increasing, monotonic
|
|
static ULONG g_head = 0; // next write slot
|
|
static KSPIN_LOCK g_lock;
|
|
static BOOLEAN g_init = FALSE;
|
|
|
|
void
|
|
gvm_log_init(void)
|
|
{
|
|
if (g_init) return;
|
|
RtlZeroMemory(g_ring, sizeof(g_ring));
|
|
KeInitializeSpinLock(&g_lock);
|
|
g_init = TRUE;
|
|
}
|
|
|
|
void
|
|
gvm_log_push(const char* fmt, ...)
|
|
{
|
|
if (!g_init) return;
|
|
char tmp[GVM_LOG_ENTRY_LEN];
|
|
va_list ap; va_start(ap, fmt);
|
|
RtlStringCbVPrintfA(tmp, sizeof(tmp), fmt, ap);
|
|
va_end(ap);
|
|
|
|
// also mirror to DbgPrint so DebugView keeps working
|
|
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[goodmans] %s\n", tmp);
|
|
|
|
LARGE_INTEGER now;
|
|
KeQuerySystemTimePrecise(&now);
|
|
|
|
KIRQL irql;
|
|
KeAcquireSpinLock(&g_lock, &irql);
|
|
gvm_log_entry* e = &g_ring[g_head];
|
|
e->timestamp_100ns = (ULONG64)now.QuadPart;
|
|
RtlStringCbCopyA(e->line, sizeof(e->line), tmp);
|
|
g_seq++;
|
|
g_head = (g_head + 1) % GVM_LOG_ENTRIES;
|
|
KeReleaseSpinLock(&g_lock, irql);
|
|
}
|
|
|
|
NTSTATUS
|
|
gvm_ioctl_tail_log(PIRP irp, PIO_STACK_LOCATION sp)
|
|
{
|
|
ULONG in_len = sp->Parameters.DeviceIoControl.InputBufferLength;
|
|
ULONG out_len = sp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
void* buf = irp->AssociatedIrp.SystemBuffer;
|
|
|
|
if (in_len < sizeof(gvm_tail_in) || out_len < sizeof(gvm_tail_out) || !buf) {
|
|
irp->IoStatus.Information = 0;
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
gvm_tail_in in;
|
|
RtlCopyMemory(&in, buf, sizeof(in));
|
|
|
|
gvm_tail_out* out = (gvm_tail_out*)ExAllocatePoolWithTag(
|
|
NonPagedPoolNx, sizeof(gvm_tail_out), 'gLog');
|
|
if (!out) return STATUS_INSUFFICIENT_RESOURCES;
|
|
RtlZeroMemory(out, sizeof(*out));
|
|
|
|
KIRQL irql;
|
|
KeAcquireSpinLock(&g_lock, &irql);
|
|
|
|
ULONG64 seq_here = g_seq;
|
|
ULONG64 want_from = in.last_seq;
|
|
ULONG64 available = 0;
|
|
|
|
if (seq_here > want_from) {
|
|
available = seq_here - want_from;
|
|
if (available > GVM_LOG_ENTRIES) {
|
|
out->dropped = (unsigned int)(available - GVM_LOG_ENTRIES);
|
|
available = GVM_LOG_ENTRIES;
|
|
}
|
|
}
|
|
|
|
// walk backwards from head, taking `available` newest entries in order
|
|
ULONG head = g_head;
|
|
for (ULONG64 i = 0; i < available; i++) {
|
|
ULONG idx = (head + GVM_LOG_ENTRIES - (ULONG)available + (ULONG)i) % GVM_LOG_ENTRIES;
|
|
out->entries[i] = g_ring[idx];
|
|
}
|
|
out->count = (unsigned int)available;
|
|
out->next_seq = seq_here;
|
|
|
|
KeReleaseSpinLock(&g_lock, irql);
|
|
|
|
RtlCopyMemory(buf, out, sizeof(*out));
|
|
ExFreePoolWithTag(out, 'gLog');
|
|
irp->IoStatus.Information = sizeof(gvm_tail_out);
|
|
return STATUS_SUCCESS;
|
|
}
|