summaryrefslogtreecommitdiff
path: root/emu/fbgl_preload.c
diff options
context:
space:
mode:
Diffstat (limited to 'emu/fbgl_preload.c')
-rw-r--r--emu/fbgl_preload.c331
1 files changed, 329 insertions, 2 deletions
diff --git a/emu/fbgl_preload.c b/emu/fbgl_preload.c
index e8771e2..485f6a6 100644
--- a/emu/fbgl_preload.c
+++ b/emu/fbgl_preload.c
@@ -1,9 +1,336 @@
#define _GNU_SOURCE
+#include "fbgl_preload.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <dlfcn.h>
#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <linux/fb.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/shm.h>
+#include <stdarg.h>
+
+// ============================================================================
+// Global State
+// ============================================================================
+
+// Framebuffer state (internal to this file)
+static fbgl_state_t g_fbgl_state = {
+ .virtual_fd = -1,
+ .shared_mem = NULL,
+ .shm_id = -1,
+ .is_initialized = 0,
+ .total_writes = 0,
+ .bytes_written = 0
+};
+
+// Original function pointers (internal to this file)
+static fbgl_original_funcs_t g_original = {
+ .open = NULL,
+ .close = NULL,
+ .ioctl = NULL,
+ .mmap = NULL,
+ .munmap = NULL,
+ .write = NULL,
+ .read = NULL
+};
+
+// ============================================================================
+// Internal Helper Functions
+// ============================================================================
+
+// Initialize original function pointers
+static void fbgl_init_hooks(void) {
+ if (!g_original.open) {
+ g_original.open = dlsym(RTLD_NEXT, "open");
+ g_original.close = dlsym(RTLD_NEXT, "close");
+ g_original.ioctl = dlsym(RTLD_NEXT, "ioctl");
+ g_original.mmap = dlsym(RTLD_NEXT, "mmap");
+ g_original.munmap = dlsym(RTLD_NEXT, "munmap");
+ g_original.write = dlsym(RTLD_NEXT, "write");
+ g_original.read = dlsym(RTLD_NEXT, "read");
+
+ if (!g_original.open || !g_original.close || !g_original.ioctl ||
+ !g_original.mmap || !g_original.munmap || !g_original.write) {
+ fprintf(stderr, "[FBGL] ERROR: Failed to load original functions\n");
+ }
+ }
+}
+
+// Initialize shared memory for framebuffer emulation
+static int fbgl_init_shared_memory(void) {
+ if (g_fbgl_state.is_initialized) {
+ return 0; // Already initialized
+ }
+
+ fprintf(stderr, "[FBGL] Attempting to create shared memory: %zu bytes\n", (size_t)FBGL_SIZE);
+
+ // First, try to remove any existing segment with this key
+ int old_id = shmget(FBGL_SHM_KEY, 0, 0);
+ if (old_id >= 0) {
+ fprintf(stderr, "[FBGL] Removing old shared memory segment (ID: %d)\n", old_id);
+ shmctl(old_id, IPC_RMID, NULL);
+ }
+
+ // Create shared memory segment (no extra space needed, shmat returns aligned memory)
+ g_fbgl_state.shm_id = shmget(FBGL_SHM_KEY, FBGL_SIZE, IPC_CREAT | IPC_EXCL | 0666);
+ if (g_fbgl_state.shm_id < 0) {
+ fprintf(stderr, "[FBGL] ERROR: Failed to create shared memory: %s (errno=%d)\n",
+ strerror(errno), errno);
+ fprintf(stderr, "[FBGL] Requested size: %zu bytes (%.2f MB)\n",
+ (size_t)FBGL_SIZE, FBGL_SIZE / (1024.0 * 1024.0));
+
+ // Try to get system limits
+ struct shminfo shm_info;
+ if (shmctl(0, IPC_INFO, (struct shmid_ds *)&shm_info) >= 0) {
+ fprintf(stderr, "[FBGL] System max shared memory: %lu bytes (%.2f MB)\n",
+ shm_info.shmmax, shm_info.shmmax / (1024.0 * 1024.0));
+ }
+ return -1;
+ }
+
+ // Attach shared memory
+ g_fbgl_state.shared_mem = shmat(g_fbgl_state.shm_id, NULL, 0);
+ if (g_fbgl_state.shared_mem == (void*)-1) {
+ fprintf(stderr, "[FBGL] ERROR: Failed to attach shared memory: %s\n",
+ strerror(errno));
+ shmctl(g_fbgl_state.shm_id, IPC_RMID, NULL);
+ g_fbgl_state.shared_mem = NULL;
+ return -1;
+ }
+
+ fprintf(stderr, "[FBGL] Shared memory attached at: %p\n", g_fbgl_state.shared_mem);
+
+ // Clear the framebuffer to black
+ memset(g_fbgl_state.shared_mem, 0, FBGL_SIZE);
+
+ g_fbgl_state.is_initialized = 1;
+
+ fprintf(stderr, "[FBGL] Initialized: %dx%d @ %d bpp, SHM ID: %d, Size: %zu bytes\n",
+ FBGL_WIDTH, FBGL_HEIGHT, FBGL_BPP, g_fbgl_state.shm_id, (size_t)FBGL_SIZE);
+
+ return 0;
+}
+
+// Check if a path is a framebuffer device
+static int fbgl_is_fb_device(const char* pathname) {
+ if (!pathname) return 0;
+
+ return (strcmp(pathname, "/dev/fb0") == 0 ||
+ strcmp(pathname, "/dev/fb") == 0 ||
+ strncmp(pathname, "/dev/fb", 7) == 0);
+}
+
+// Check if a file descriptor is our virtual framebuffer
+static int fbgl_is_virtual_fd(int fd) {
+ return (fd == g_fbgl_state.virtual_fd && fd != -1);
+}
+
+// Fill fb_var_screeninfo structure
+static void fbgl_fill_var_screeninfo(struct fb_var_screeninfo* vinfo) {
+ memset(vinfo, 0, sizeof(*vinfo));
+
+ vinfo->xres = FBGL_WIDTH;
+ vinfo->yres = FBGL_HEIGHT;
+ vinfo->xres_virtual = FBGL_WIDTH;
+ vinfo->yres_virtual = FBGL_HEIGHT;
+ vinfo->bits_per_pixel = FBGL_BPP;
+
+ // ARGB8888 format
+ vinfo->red.offset = 16;
+ vinfo->red.length = 8;
+ vinfo->green.offset = 8;
+ vinfo->green.length = 8;
+ vinfo->blue.offset = 0;
+ vinfo->blue.length = 8;
+ vinfo->transp.offset = 24;
+ vinfo->transp.length = 8;
+}
+
+// Fill fb_fix_screeninfo structure
+static void fbgl_fill_fix_screeninfo(struct fb_fix_screeninfo* finfo) {
+ memset(finfo, 0, sizeof(*finfo));
+
+ strncpy(finfo->id, "FBGL_EMU", sizeof(finfo->id) - 1);
+ finfo->smem_len = FBGL_SIZE;
+ finfo->type = FB_TYPE_PACKED_PIXELS;
+ finfo->visual = FB_VISUAL_TRUECOLOR;
+ finfo->line_length = FBGL_PITCH;
+}
-int open(const char *pathname, int flags);
+// ============================================================================
+// Hooked Functions (Public - must NOT be static!)
+// ============================================================================
-int open(const char *pathname, int flags) {
+int open(const char* pathname, int flags, ...) {
+ fbgl_init_hooks();
+
+ // Check if opening framebuffer device
+ if (fbgl_is_fb_device(pathname)) {
+ if (fbgl_init_shared_memory() < 0) {
+ errno = EIO;
+ return -1;
+ }
+
+ g_fbgl_state.virtual_fd = FBGL_VIRTUAL_FD;
+ fprintf(stderr, "[FBGL] open(\"%s\") -> virtual fd %d\n",
+ pathname, g_fbgl_state.virtual_fd);
+ return g_fbgl_state.virtual_fd;
+ }
+
+ // Pass through to original open
+ mode_t mode = 0;
+ if (flags & O_CREAT) {
+ va_list args;
+ va_start(args, flags);
+ mode = va_arg(args, mode_t);
+ va_end(args);
+ return g_original.open(pathname, flags, mode);
+ }
+ return g_original.open(pathname, flags);
+}
+
+int close(int fd) {
+ fbgl_init_hooks();
+
+ if (fbgl_is_virtual_fd(fd)) {
+ fprintf(stderr, "[FBGL] close(fb) - keeping shared memory alive\n");
+ g_fbgl_state.virtual_fd = -1;
+ return 0;
+ }
+
+ return g_original.close(fd);
+}
+
+int ioctl(int fd, unsigned long request, ...) {
+ fbgl_init_hooks();
+
+ if (fbgl_is_virtual_fd(fd)) {
+ va_list args;
+ va_start(args, request);
+ void* argp = va_arg(args, void*);
+ va_end(args);
+
+ fprintf(stderr, "[FBGL] ioctl(fb, 0x%lx)\n", request);
+
+ switch (request) {
+ case FBIOGET_VSCREENINFO:
+ fbgl_fill_var_screeninfo((struct fb_var_screeninfo*)argp);
+ return 0;
+
+ case FBIOGET_FSCREENINFO:
+ fbgl_fill_fix_screeninfo((struct fb_fix_screeninfo*)argp);
+ return 0;
+
+ case FBIOPUT_VSCREENINFO:
+ // Ignore changes to screen info
+ fprintf(stderr, "[FBGL] ioctl: FBIOPUT_VSCREENINFO ignored\n");
+ return 0;
+
+ default:
+ fprintf(stderr, "[FBGL] ioctl: Unknown request 0x%lx\n", request);
+ return 0;
+ }
+ }
+
+ // Pass through to original ioctl
+ va_list args;
+ va_start(args, request);
+ void* argp = va_arg(args, void*);
+ va_end(args);
+ return g_original.ioctl(fd, request, argp);
+}
+
+void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset) {
+ fbgl_init_hooks();
+
+ if (fbgl_is_virtual_fd(fd)) {
+ if (!g_fbgl_state.shared_mem) {
+ fprintf(stderr, "[FBGL] ERROR: mmap called but shared memory not initialized\n");
+ errno = ENOMEM;
+ return MAP_FAILED;
+ }
+
+ fprintf(stderr, "[FBGL] mmap(fb, %zu bytes, offset=%ld) -> %p\n",
+ length, offset, g_fbgl_state.shared_mem);
+ return g_fbgl_state.shared_mem;
+ }
+
+ return g_original.mmap(addr, length, prot, flags, fd, offset);
+}
+
+int munmap(void* addr, size_t length) {
+ fbgl_init_hooks();
+
+ if (addr == g_fbgl_state.shared_mem) {
+ fprintf(stderr, "[FBGL] munmap(fb) - keeping shared memory attached\n");
+ return 0;
+ }
+
+ return g_original.munmap(addr, length);
+}
+
+ssize_t write(int fd, const void* buf, size_t count) {
+ fbgl_init_hooks();
+
+ if (fbgl_is_virtual_fd(fd) && g_fbgl_state.shared_mem && buf) {
+ size_t to_write = (count < FBGL_SIZE) ? count : FBGL_SIZE;
+ memcpy(g_fbgl_state.shared_mem, buf, to_write);
+
+ g_fbgl_state.total_writes++;
+ g_fbgl_state.bytes_written += to_write;
+
+ fprintf(stderr, "[FBGL] write(fb, %zu bytes) - total writes: %zu\n",
+ to_write, g_fbgl_state.total_writes);
+ return to_write;
+ }
+
+ return g_original.write(fd, buf, count);
+}
+
+ssize_t read(int fd, void* buf, size_t count) {
+ fbgl_init_hooks();
+
+ if (fbgl_is_virtual_fd(fd) && g_fbgl_state.shared_mem && buf) {
+ size_t to_read = (count < FBGL_SIZE) ? count : FBGL_SIZE;
+ memcpy(buf, g_fbgl_state.shared_mem, to_read);
+ return to_read;
+ }
+
+ return g_original.read(fd, buf, count);
+}
+
+// ============================================================================
+// Constructor/Destructor
+// ============================================================================
+
+__attribute__((constructor))
+static void fbgl_constructor(void) {
+ fprintf(stderr, "========================================\n");
+ fprintf(stderr, "FBGL Framebuffer Emulator v1.0\n");
+ fprintf(stderr, "Configuration: %dx%d @ %d bpp\n",
+ FBGL_WIDTH, FBGL_HEIGHT, FBGL_BPP);
+ fprintf(stderr, "Shared Memory Key: 0x%08X\n", FBGL_SHM_KEY);
+ fprintf(stderr, "========================================\n");
+}
+__attribute__((destructor))
+static void fbgl_destructor(void) {
+ fprintf(stderr, "\n========================================\n");
+ fprintf(stderr, "FBGL Statistics:\n");
+ fprintf(stderr, " Total writes: %zu\n", g_fbgl_state.total_writes);
+ fprintf(stderr, " Bytes written: %zu\n", g_fbgl_state.bytes_written);
+ fprintf(stderr, "========================================\n");
+
+ if (g_fbgl_state.shared_mem && g_fbgl_state.shared_mem != (void*)-1) {
+ shmdt(g_fbgl_state.shared_mem);
+ g_fbgl_state.shared_mem = NULL;
+ }
}