mirror of
https://github.com/valentderah/totk-pc-recomp.git
synced 2026-11-11 01:41:02 +00:00
Shared runtime code now goes through runtime/platform/platform.h, implemented by platform/win32.c and a new platform/linux.c: futex locks, a userfaultfd and PAGEMAP_SCAN write watch, signal-based async preemption, our own fiber switch, and a SIGSEGV handler for the thaw and crash hooks. The window, input, menu and software keyboard get SDL3 back ends beside the Win32 ones, with the swapchain (gfx_present.c) and input merging (input.c) shared. SHA-256 replaces BCrypt, ELF builds get their own override sections, and the build tools gain Linux branches. On Linux the selftest and the gfx-abi, astc, nvn and window probes pass. probe-vkmem still fails: imported guest memory cannot be write-watched on Linux, which the shadow buffers in vk_memory.c will address.
79 lines
2.9 KiB
C
79 lines
2.9 KiB
C
// NVN proc table. Every name the game's proc loader asks for gets a synthetic host
|
|
// address through hostfn_register before hostfn_seal; nvnBootstrapLoader and nvnDeviceGetProcAddress hand them out.
|
|
// nvnp_<name> is the implementation of one proc: the weak definitions here stop with the proc's name, nvn_api_*.c
|
|
// and nvn_ext.c define the strong ones. The name list is runtime/nvn_procs.inc (tools/gen_nvn_procs.py).
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "gfx.h"
|
|
#include "host.h"
|
|
#include "platform/platform.h"
|
|
|
|
// The strong nvnp_nvnDeviceGetProcAddress below replaces the stand-in generated for the same row.
|
|
#define nvnp_nvnDeviceGetProcAddress nvnp_stub_nvnDeviceGetProcAddress
|
|
|
|
#define NVN_PROC(n) void nvnp_##n(Cpu *c);
|
|
#include "nvn_procs.inc"
|
|
#undef NVN_PROC
|
|
|
|
#define NVN_PROC(n) \
|
|
__attribute__((weak)) void nvnp_##n(Cpu *c) { \
|
|
(void)c; \
|
|
rt_fatal("NVN " #n " is not implemented"); \
|
|
}
|
|
#include "nvn_procs.inc"
|
|
#undef NVN_PROC
|
|
#undef nvnp_nvnDeviceGetProcAddress
|
|
void nvnp_nvnDeviceGetProcAddress(Cpu *c);
|
|
|
|
typedef struct { const char *name; uint64_t addr; } Proc;
|
|
|
|
#define NVN_PROC(n) +1
|
|
enum { PROC_COUNT = 0
|
|
#include "nvn_procs.inc"
|
|
};
|
|
#undef NVN_PROC
|
|
|
|
static Proc procs[PROC_COUNT];
|
|
static int nprocs;
|
|
|
|
static int by_name(const void *a, const void *b) { return strcmp(((const Proc *)a)->name, ((const Proc *)b)->name); }
|
|
|
|
void nvn_procs_register(void) {
|
|
if (nprocs) return;
|
|
#define NVN_PROC(n) procs[nprocs++] = (Proc){#n, hostfn_register("nvn:" #n, nvnp_##n)};
|
|
#include "nvn_procs.inc"
|
|
#undef NVN_PROC
|
|
qsort(procs, (size_t)nprocs, sizeof *procs, by_name);
|
|
}
|
|
|
|
uint64_t nvn_proc_address(const char *name) {
|
|
if (!name) return 0;
|
|
const Proc *p = bsearch(&(Proc){name, 0}, procs, (size_t)nprocs, sizeof *procs, by_name);
|
|
if (p) return p->addr;
|
|
// Unknown names get NULL, as on hardware; each distinct one is logged once.
|
|
static PlatMutex lock = PLAT_MUTEX_INIT;
|
|
static char seen[32][96];
|
|
static int nseen;
|
|
plat_mutex_lock(&lock);
|
|
int fresh = 1;
|
|
for (int i = 0; i < nseen; i++)
|
|
if (!strncmp(seen[i], name, sizeof seen[i] - 1)) fresh = 0;
|
|
if (fresh && nseen < 32) {
|
|
strncpy(seen[nseen], name, sizeof seen[0] - 1);
|
|
nseen++;
|
|
} else {
|
|
fresh = 0;
|
|
}
|
|
plat_mutex_unlock(&lock);
|
|
if (fresh) rt_log("nvn: no such proc \"%s\", returning NULL", name);
|
|
return 0;
|
|
}
|
|
|
|
// PFNNVNGENERICFUNC nvnDeviceGetProcAddress(const NVNdevice *device, const char *name)
|
|
void nvnp_nvnDeviceGetProcAddress(Cpu *c) {
|
|
const char *name = arg_p(c, 1);
|
|
ret_x(c, nvn_proc_address(name));
|
|
}
|