mirror of
https://github.com/zer0condition/GoodmansKernel/
synced 2026-08-19 01:14:35 +00:00
initial commit
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
/* module_table.c - fixed-size slot allocator for loaded modules.
|
||||
* refcount is atomic (LONG). teardown holds the module's call_mutex so
|
||||
* any in-flight m3_Call has to finish before the runtime is freed. */
|
||||
#include "inc/gvm.h"
|
||||
#include "../shared/goodmans_ioctl.h"
|
||||
|
||||
static gvm_module g_modules[GVM_MAX_MODULES];
|
||||
static KSPIN_LOCK g_lock;
|
||||
|
||||
NTSTATUS
|
||||
gvm_modtab_init(void)
|
||||
{
|
||||
RtlZeroMemory(g_modules, sizeof(g_modules));
|
||||
KeInitializeSpinLock(&g_lock);
|
||||
// init every mutex up front so iterators that wait on all slots (e.g. the
|
||||
// callback dispatch worker) don't touch an uninitialized DISPATCHER_HEADER
|
||||
for (unsigned int i = 0; i < GVM_MAX_MODULES; i++)
|
||||
KeInitializeMutex(&g_modules[i].call_mutex, 0);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
gvm_modtab_teardown(void)
|
||||
{
|
||||
for (unsigned int i = 0; i < GVM_MAX_MODULES; i++) {
|
||||
if (g_modules[i].used) {
|
||||
g_modules[i].refcount = 1; // force teardown
|
||||
gvm_modtab_free(&g_modules[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gvm_module*
|
||||
gvm_modtab_alloc(void)
|
||||
{
|
||||
KIRQL irql;
|
||||
gvm_module* out = NULL;
|
||||
|
||||
KeAcquireSpinLock(&g_lock, &irql);
|
||||
for (unsigned int i = 0; i < GVM_MAX_MODULES; i++) {
|
||||
if (!g_modules[i].used) {
|
||||
g_modules[i].used = TRUE;
|
||||
g_modules[i].id = i + 1;
|
||||
g_modules[i].refcount = 1;
|
||||
KeInitializeMutex(&g_modules[i].call_mutex, 0);
|
||||
out = &g_modules[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
KeReleaseSpinLock(&g_lock, irql);
|
||||
return out;
|
||||
}
|
||||
|
||||
gvm_module*
|
||||
gvm_modtab_get(unsigned int id)
|
||||
{
|
||||
if (id == 0 || id > GVM_MAX_MODULES) return NULL;
|
||||
gvm_module* m = &g_modules[id - 1];
|
||||
return m->used ? m : NULL;
|
||||
}
|
||||
|
||||
gvm_module*
|
||||
gvm_modtab_find_by_hash(unsigned long long hash)
|
||||
{
|
||||
KIRQL irql;
|
||||
gvm_module* out = NULL;
|
||||
|
||||
KeAcquireSpinLock(&g_lock, &irql);
|
||||
for (unsigned int i = 0; i < GVM_MAX_MODULES; i++) {
|
||||
if (g_modules[i].used && g_modules[i].hash == hash) {
|
||||
out = &g_modules[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
KeReleaseSpinLock(&g_lock, irql);
|
||||
return out;
|
||||
}
|
||||
|
||||
// atomic find + increment under the table lock. safer than
|
||||
// find_by_hash + separate refcount++ which races with concurrent unload.
|
||||
gvm_module*
|
||||
gvm_modtab_find_by_hash_incref(unsigned long long hash, unsigned int expected_size)
|
||||
{
|
||||
KIRQL irql;
|
||||
gvm_module* out = NULL;
|
||||
|
||||
KeAcquireSpinLock(&g_lock, &irql);
|
||||
for (unsigned int i = 0; i < GVM_MAX_MODULES; i++) {
|
||||
if (g_modules[i].used
|
||||
&& g_modules[i].hash == hash
|
||||
&& g_modules[i].wasm_size == expected_size) {
|
||||
InterlockedIncrement(&g_modules[i].refcount);
|
||||
out = &g_modules[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
KeReleaseSpinLock(&g_lock, irql);
|
||||
return out;
|
||||
}
|
||||
|
||||
gvm_module*
|
||||
gvm_modtab_iter(unsigned int idx)
|
||||
{
|
||||
if (idx >= GVM_MAX_MODULES) return NULL;
|
||||
return &g_modules[idx];
|
||||
}
|
||||
|
||||
gvm_module*
|
||||
gvm_modtab_owner_of_runtime(IM3Runtime rt)
|
||||
{
|
||||
if (!rt) return NULL;
|
||||
for (unsigned int i = 0; i < GVM_MAX_MODULES; i++) {
|
||||
if (g_modules[i].used && g_modules[i].runtime == rt)
|
||||
return &g_modules[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
gvm_modtab_free(gvm_module* m)
|
||||
{
|
||||
if (!m || !m->used) return;
|
||||
|
||||
// only the last reference proceeds to teardown
|
||||
if (InterlockedDecrement(&m->refcount) > 0) return;
|
||||
|
||||
// block until any in-flight m3_Call finishes so the runtime is quiescent
|
||||
KeWaitForSingleObject(&m->call_mutex, Executive, KernelMode, FALSE, NULL);
|
||||
|
||||
if (m->runtime) {
|
||||
m3_FreeRuntime(m->runtime);
|
||||
m->runtime = NULL;
|
||||
}
|
||||
if (m->env) {
|
||||
m3_FreeEnvironment(m->env);
|
||||
m->env = NULL;
|
||||
}
|
||||
if (m->wasm_bytes) {
|
||||
ExFreePoolWithTag(m->wasm_bytes, GVM_TAG_WBUF);
|
||||
m->wasm_bytes = NULL;
|
||||
}
|
||||
m->module = NULL;
|
||||
m->wasm_size = 0;
|
||||
m->hash = 0;
|
||||
|
||||
// publish used=FALSE before releasing so waiters see it on retry
|
||||
m->used = FALSE;
|
||||
|
||||
KeReleaseMutex(&m->call_mutex, FALSE);
|
||||
}
|
||||
Reference in New Issue
Block a user