lightrec: Add new memory init functions
authorPaul Cercueil <paul@crapouillou.net>
Wed, 11 May 2022 15:54:16 +0000 (16:54 +0100)
committerPaul Cercueil <paul@crapouillou.net>
Sat, 28 May 2022 10:55:00 +0000 (11:55 +0100)
Lightrec can greatly benefit from having the RAM/BIOS/scratchpad and RAM
mirrors mapped to specific addresses. For the same value of (offset):

- If the RAM is mapped to (offset), the BIOS is mapped to
  (offset + 0x1fc00000) and the scratchpad to (offset + 0x1f800000), the
  generated code will be better;

- If the RAM is also mirrored to (offset + 0x200000), (offset + 0x400000)
  and (offset + 0x600000), the generated code will be even better;

- If the offset is 0x0, the generated code will be even better.

Additionally, the new memory init code will attempt to use huge pages
when possible, in order to greatly reduce the overhead of the MMU.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Makefile
Makefile.libretro
libpcsxcore/lightrec/mem.c [new file with mode: 0644]
libpcsxcore/lightrec/mem.h [new file with mode: 0644]

index 6a83f46..bff1a1c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -47,6 +47,8 @@ ifdef PCNT
 CFLAGS += -DPCNT
 endif
 
+LIGHTREC_CUSTOM_MAP ?= 0
+
 # core
 OBJS += libpcsxcore/cdriso.o libpcsxcore/cdrom.o libpcsxcore/cheat.o libpcsxcore/database.o \
        libpcsxcore/decode_xa.o libpcsxcore/mdec.o \
@@ -89,7 +91,12 @@ libpcsxcore/psxbios.o: CFLAGS += -Wno-nonnull
 # dynarec
 ifeq "$(DYNAREC)" "lightrec"
 CFLAGS += -Ideps/lightning/include -Ideps/lightrec -Iinclude/lightning -Iinclude/lightrec \
-                 -DLIGHTREC -DLIGHTREC_STATIC
+                 -DLIGHTREC -DLIGHTREC_STATIC \
+                 -DLIGHTREC_CUSTOM_MAP=$(LIGHTREC_CUSTOM_MAP)
+LDLIBS += -lrt
+ifeq ($(LIGHTREC_CUSTOM_MAP),1)
+OBJS += libpcsxcore/lightrec/mem.o
+endif
 OBJS += libpcsxcore/lightrec/plugin.o
 OBJS += deps/lightning/lib/jit_disasm.o \
                deps/lightning/lib/jit_memory.o \
@@ -108,6 +115,7 @@ OBJS += deps/lightning/lib/jit_disasm.o \
                deps/lightrec/regcache.o \
                deps/lightrec/recompiler.o \
                deps/lightrec/reaper.o
+libpcsxcore/lightrec/mem.o: CFLAGS += -D_GNU_SOURCE
 ifeq ($(MMAP_WIN32),1)
 CFLAGS += -Iinclude/mman
 OBJS += deps/mman/mman.o
index dd89682..3edda64 100644 (file)
@@ -51,6 +51,9 @@ ifeq ($(platform), unix)
        TARGET := $(TARGET_NAME)_libretro.so
        fpic := -fPIC
        THREAD_RENDERING = 1
+ifeq ($(shell uname),Linux)
+       LIGHTREC_CUSTOM_MAP := 1
+endif
 ifneq ($(findstring SunOS,$(shell uname -s)),)
        CC = gcc
 endif
@@ -92,6 +95,7 @@ else ifeq ($(platform), linux-portable)
        LIBDL :=
        LIBM :=
        NO_UNDEF_CHECK = 1
+       LIGHTREC_CUSTOM_MAP := 1
 
 # OS X
 else ifeq ($(platform), osx)
diff --git a/libpcsxcore/lightrec/mem.c b/libpcsxcore/lightrec/mem.c
new file mode 100644 (file)
index 0000000..76608ea
--- /dev/null
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ * Copyright (C) 2022 Paul Cercueil <paul@crapouillou.net>
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/shm.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "../psxhw.h"
+#include "../psxmem.h"
+#include "../r3000a.h"
+
+#include "mem.h"
+
+#define ARRAY_SIZE(a) (sizeof(a) ? (sizeof(a) / sizeof((a)[0])) : 0)
+
+#ifndef MAP_FIXED_NOREPLACE
+#define MAP_FIXED_NOREPLACE 0x100000
+#endif
+
+static const uintptr_t supported_io_bases[] = {
+       0x0,
+       0x10000000,
+       0x40000000,
+       0x80000000,
+};
+
+static void * mmap_huge(void *addr, size_t length, int prot, int flags,
+                       int fd, off_t offset)
+{
+       void *map = MAP_FAILED;
+
+       if (length >= 0x200000) {
+               map = mmap(addr, length, prot,
+                          flags | MAP_HUGETLB | (21 << MAP_HUGE_SHIFT),
+                          fd, offset);
+               if (map != MAP_FAILED)
+                       printf("Hugetlb mmap to address 0x%lx succeeded\n", (uintptr_t) addr);
+       }
+
+       if (map == MAP_FAILED) {
+               map = mmap(addr, length, prot, flags, fd, offset);
+               if (map != MAP_FAILED)
+                       printf("Regular mmap to address 0x%lx succeeded\n", (uintptr_t) addr);
+       }
+
+       return map;
+}
+
+static int lightrec_mmap_ram(bool hugetlb)
+{
+       unsigned int i, j;
+       int err, memfd, flags = 0;
+       uintptr_t base;
+       void *map;
+
+       if (hugetlb)
+               flags |= MFD_HUGETLB;
+
+       memfd = memfd_create("/lightrec_memfd", flags);
+       if (memfd < 0) {
+               err = -errno;
+               fprintf(stderr, "Failed to create memfd: %d\n", err);
+               return err;
+       }
+
+       err = ftruncate(memfd, 0x200000);
+       if (err < 0) {
+               err = -errno;
+               fprintf(stderr, "Could not trim memfd: %d\n", err);
+               goto err_close_memfd;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(supported_io_bases); i++) {
+               base = supported_io_bases[i];
+
+               for (j = 0; j < 4; j++) {
+                       map = mmap_huge((void *)(base + j * 0x200000),
+                                       0x200000, PROT_READ | PROT_WRITE,
+                                       MAP_SHARED | MAP_FIXED, memfd, 0);
+                       if (map == MAP_FAILED)
+                               break;
+               }
+
+               /* Impossible to map using this base */
+               if (j == 0)
+                       continue;
+
+               /* All mirrors mapped - we got a match! */
+               if (j == 4)
+                       break;
+
+               /* Only some mirrors mapped - clean the mess and try again */
+               for (; j > 0; j--)
+                       munmap((void *)(base + (j - 1) * 0x200000), 0x200000);
+       }
+
+       if (i == ARRAY_SIZE(supported_io_bases)) {
+               err = -EINVAL;
+               goto err_close_memfd;
+       }
+
+       err = 0;
+       psxM = (s8 *)base;
+
+err_close_memfd:
+       close(memfd);
+       return err;
+}
+
+int lightrec_init_mmap(void)
+{
+       unsigned int i;
+       uintptr_t base;
+       void *map;
+       int err;
+
+       err = lightrec_mmap_ram(true);
+       if (err) {
+               err = lightrec_mmap_ram(false);
+               if (err) {
+                       fprintf(stderr, "Unable to mmap RAM and mirrors\n");
+                       return err;
+               }
+       }
+
+       base = (uintptr_t) psxM;
+
+       map = mmap((void *)(base + 0x1f000000), 0x10000,
+                  PROT_READ | PROT_WRITE,
+                  MAP_PRIVATE | MAP_FIXED_NOREPLACE | MAP_ANONYMOUS, 0, 0);
+       if (map == MAP_FAILED) {
+               err = -EINVAL;
+               fprintf(stderr, "Unable to mmap parallel port\n");
+               goto err_unmap;
+       }
+
+       psxP = (s8 *)map;
+
+       map = mmap_huge((void *)(base + 0x1fc00000), 0x200000,
+                       PROT_READ | PROT_WRITE,
+                       MAP_PRIVATE | MAP_FIXED_NOREPLACE | MAP_ANONYMOUS, 0, 0);
+       if (map == MAP_FAILED) {
+               err = -EINVAL;
+               fprintf(stderr, "Unable to mmap BIOS\n");
+               goto err_unmap_parallel;
+       }
+
+       psxR = (s8 *)map;
+
+       map = mmap((void *)(base + 0x1f800000), 0x10000,
+                  PROT_READ | PROT_WRITE,
+                  MAP_PRIVATE | MAP_FIXED_NOREPLACE | MAP_ANONYMOUS, 0, 0);
+       if (map == MAP_FAILED) {
+               err = -EINVAL;
+               fprintf(stderr, "Unable to mmap scratchpad\n");
+               goto err_unmap_bios;
+       }
+
+       psxH = (s8 *)map;
+
+       return 0;
+
+err_unmap_bios:
+       munmap(psxR, 0x80000);
+err_unmap_parallel:
+       munmap(psxP, 0x10000);
+err_unmap:
+       for (i = 0; i < 4; i++)
+               munmap((void *)((uintptr_t)psxM + i * 0x200000), 0x200000);
+       return err;
+}
+
+void lightrec_free_mmap(void)
+{
+       unsigned int i;
+
+       munmap(psxH, 0x10000);
+       munmap(psxR, 0x80000);
+       munmap(psxP, 0x10000);
+       for (i = 0; i < 4; i++)
+               munmap((void *)((uintptr_t)psxM + i * 0x200000), 0x200000);
+}
diff --git a/libpcsxcore/lightrec/mem.h b/libpcsxcore/lightrec/mem.h
new file mode 100644 (file)
index 0000000..7f04ce5
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2022 Paul Cercueil <paul@crapouillou.net>
+ */
+
+#ifndef __LIGHTREC_MEM_H__
+#define __LIGHTREC_MEM_H__
+
+int lightrec_init_mmap(void);
+void lightrec_free_mmap(void);
+
+#endif /* __LIGHTREC_MEM_H__ */