Files
Wellington Dias 1d51343ac1 Build and run the runtime natively on Linux.
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.
2026-10-29 16:56:56 -03:00

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));
}