Files
Espresso/lib/ksymtab.c

125 lines
2.4 KiB
C
Raw Normal View History

2025-07-03 20:30:21 -05:00
#include <ksymtab.h>
2025-07-04 14:23:29 -05:00
2025-07-03 20:30:21 -05:00
#define KFUNC_TABLE_ADDRESS 0xC0101000
2025-07-04 14:23:29 -05:00
#define KSYMTAB_MAX 0x8086FF
2025-07-03 20:30:21 -05:00
#define IS_MODULE_FUNC(id) ((id) & 0x80000000)
#define GET_MODULE_ID(id) (((id) >> 20) & 0x7FF)
#define GET_FUNC_ID(id) ((id) & 0xFFFFF)
#define EXISTS(id) ((id) > 0x0)
#define MAKE_KERNEL_FUNC(id) ((id) & 0x7FFFFFFF)
#define MAKE_MODULE_FUNC(mid, fid) (0x80000000 | ((mid) << 20) | ((fid) & 0xFFFFF))
kfunc_t* kfunc_table = (kfunc_t*)KFUNC_TABLE_ADDRESS;
2025-07-04 14:23:29 -05:00
static uint32_t ktab_size = 0;
2025-07-03 20:30:21 -05:00
uint64_t kfunc_call(kfunc_t* func, uint32_t a, uint32_t b, uint32_t c, uint32_t d)
{
uint32_t eax_ret, edx_ret;
asm volatile (
"push %[d]\n\t"
"push %[c]\n\t"
"push %[b]\n\t"
"push %[a]\n\t"
"call *%[fn]\n\t"
"add $16, %%esp\n\t" /* clean up stack (4 args * 4 bytes) */
: "=a"(eax_ret), "=d"(edx_ret)
: [a]"r"(a), [b]"r"(b), [c]"r"(c), [d]"r"(d), [fn]"r"(func->addr)
: "memory"
);
return ((uint64_t)edx_ret << 32) | eax_ret;
}
uint64_t call_kfunc_by_id(uint32_t id, uint32_t a, uint32_t b, uint32_t c, uint32_t d)
{
2025-07-04 14:23:29 -05:00
for (int i = 0; i < (int)ktab_size; i++)
2025-07-03 20:30:21 -05:00
{
if (kfunc_table[i].id == id)
{
if (kfunc_table[i].addr == 0x0)
{
return -1;
}
return kfunc_call(&kfunc_table[i], a, b, c, d);
}
}
return -1;
}
2025-07-04 14:23:29 -05:00
uint32_t add_kfunc(void* addr, bool module, uint16_t module_id, uint32_t function_id)
{
if (ktab_size >= KSYMTAB_MAX)
{
return 0xFFFFFFFF;
}
kfunc_t kf = make_kfunc(addr, module, module_id, function_id);
kfunc_table[ktab_size] = kf;
ktab_size++;
return kf.id;
}
/*
Constructs and returns a kfunc_t:
- 'addr' is the address of the function (can be NULL/0)
- 'module' indicates if it's a module/driver function
- 'module_id' is used only if 'module' is true (11 bits max)
- 'function_id':
- 20 bits if module is true
- 31 bits if kernel function
*/
kfunc_t make_kfunc(void* addr, bool module, uint16_t module_id, uint32_t function_id)
{
uint32_t id;
if (module)
{
id = 0x80000000 | ((module_id & 0x7FF) << 20) | (function_id & 0xFFFFF);
}
else
{
if (function_id == UINT32_MAX)
{
function_id = ktab_size;
}
id = function_id & 0x7FFFFFFF;
}
kfunc_t result = {
.id = id,
.addr = (uint32_t)(uintptr_t)addr
};
return result;
}
kfunc_t* find_kfunc(uint32_t id)
{
for (uint32_t i = 0; i < ktab_size; i++)
{
if (kfunc_table[i].id == id)
{
return &kfunc_table[i];
}
}
return NULL;
}