new 3ds_mmap, avoid useless retries
authornotaz <notasas@gmail.com>
Mon, 30 Sep 2024 18:14:41 +0000 (21:14 +0300)
committernotaz <notasas@gmail.com>
Mon, 30 Sep 2024 18:14:41 +0000 (21:14 +0300)
frontend/libretro.c
frontend/plat_pollux.c
frontend/plugin_lib.c
libpcsxcore/psxmem.c
libpcsxcore/psxmem_map.h

index 90f40a6..dd45d16 100644 (file)
@@ -387,54 +387,78 @@ out:
 }
 
 #ifdef _3DS
-typedef struct
-{
-   void *buffer;
-   uint32_t target_map;
-   size_t size;
-   enum psxMapTag tag;
-} psx_map_t;
-
-psx_map_t custom_psx_maps[] = {
-   { NULL, 0x13000000, 0x210000, MAP_TAG_RAM }, // 0x80000000
-   { NULL, 0x12800000, 0x010000, MAP_TAG_OTHER }, // 0x1f800000
-   { NULL, 0x12c00000, 0x080000, MAP_TAG_OTHER }, // 0x1fc00000
-   { NULL, 0x11000000, 0x800000, MAP_TAG_LUTS }, // 0x08000000
-   { NULL, 0x12000000, 0x201000, MAP_TAG_VRAM }, // 0x00000000
-};
+static u32 mapped_addrs[8];
+static u32 mapped_ram, mapped_ram_src;
 
-void *pl_3ds_mmap(unsigned long addr, size_t size, int is_fixed,
-    enum psxMapTag tag)
+// http://3dbrew.org/wiki/Memory_layout#ARM11_User-land_memory_regions
+void *pl_3ds_mmap(unsigned long addr, size_t size,
+    enum psxMapTag tag, int *can_retry_addr)
 {
-   (void)is_fixed;
    (void)addr;
+   *can_retry_addr = 0;
 
-   if (__ctr_svchax)
+   if (__ctr_svchax) do
    {
-      psx_map_t *custom_map = custom_psx_maps;
+      // idea from fbalpha2012_neogeo
+      s32 addr = 0x10000000 - 0x1000;
+      u32 found_addr = 0;
+      MemInfo mem_info;
+      PageInfo page_info;
+      void *ret = NULL;
+      size_t i;
+      int r;
+
+      for (i = 0; i < sizeof(mapped_addrs) / sizeof(mapped_addrs[0]); i++)
+         if (mapped_addrs[i] == 0)
+            break;
+      if (i == sizeof(mapped_addrs) / sizeof(mapped_addrs[0]))
+         break;
+
+      size = (size + 0xfff) & ~0xfff;
 
-      for (; custom_map->size; custom_map++)
+      while (addr >= 0x08000000)
       {
-         if ((custom_map->size == size) && (custom_map->tag == tag))
-         {
-            uint32_t ptr_aligned, tmp;
-            void *ret;
+         if ((r = svcQueryMemory(&mem_info, &page_info, addr)) < 0) {
+            LogErr("svcQueryMemory failed: %d\n", r);
+            break;
+         }
 
-            custom_map->buffer = malloc(size + 0x1000);
-            ptr_aligned = (((u32)custom_map->buffer) + 0xFFF) & ~0xFFF;
+         if (mem_info.state == MEMSTATE_FREE && mem_info.size >= size) {
+            found_addr = mem_info.base_addr + mem_info.size - size;
+            break;
+         }
 
-            if (svcControlMemory(&tmp, (void *)custom_map->target_map, (void *)ptr_aligned, size, MEMOP_MAP, 0x3) < 0)
-            {
-               LogErr("could not map memory @0x%08X\n", custom_map->target_map);
-               exit(1);
-            }
+         addr = mem_info.base_addr - 0x1000;
+      }
+      if (found_addr == 0) {
+         LogErr("no addr space for %u bytes\n", size);
+         break;
+      }
 
-            ret = (void *)custom_map->target_map;
-            memset(ret, 0, size);
-            return ret;
+      // https://libctru.devkitpro.org/svc_8h.html#a8046e9b23b1b209a4e278cb1c19c7a5a
+      if ((r = svcControlMemory(&mapped_addrs[i], found_addr, 0, size, MEMOP_ALLOC, MEMPERM_READWRITE)) < 0) {
+         LogErr("svcControlMemory failed for %08x %u: %d\n", found_addr, size, r);
+         break;
+      }
+      if (mapped_addrs[i] == 0) // needed?
+         mapped_addrs[i] = found_addr;
+      ret = (void *)mapped_addrs[i];
+
+      // "round" address helps the dynarec slightly, map ram at 0x13000000
+      if (tag == MAP_TAG_RAM && !mapped_ram) {
+         u32 target = 0x13000000;
+         if ((r = svcControlMemory(&mapped_ram, target, mapped_addrs[i], size, MEMOP_MAP, MEMPERM_READWRITE)) < 0)
+            LogErr("could not map ram %08x -> %08x: %d\n", mapped_addrs[i], target, r);
+         else {
+            mapped_ram_src = mapped_addrs[i];
+            mapped_ram = target;
+            ret = (void *)mapped_ram;
          }
       }
+      memset(ret, 0, size);
+      return ret;
    }
+   while (0);
 
    return calloc(size, 1);
 }
@@ -443,22 +467,22 @@ void pl_3ds_munmap(void *ptr, size_t size, enum psxMapTag tag)
 {
    (void)tag;
 
-   if (__ctr_svchax)
+   if (ptr && __ctr_svchax)
    {
-      psx_map_t *custom_map = custom_psx_maps;
-
-      for (; custom_map->size; custom_map++)
-      {
-         if ((custom_map->target_map == (uint32_t)ptr))
-         {
-            uint32_t ptr_aligned, tmp;
+      size_t i;
+      u32 tmp;
 
-            ptr_aligned = (((u32)custom_map->buffer) + 0xFFF) & ~0xFFF;
+      size = (size + 0xfff) & ~0xfff;
 
-            svcControlMemory(&tmp, (void *)custom_map->target_map, (void *)ptr_aligned, size, MEMOP_UNMAP, 0x3);
-
-            free(custom_map->buffer);
-            custom_map->buffer = NULL;
+      if (ptr == (void *)mapped_ram) {
+         svcControlMemory(&tmp, mapped_ram, mapped_ram_src, size, MEMOP_UNMAP, 0);
+         ptr = (void *)mapped_ram_src;
+         mapped_ram = mapped_ram_src = 0;
+      }
+      for (i = 0; i < sizeof(mapped_addrs) / sizeof(mapped_addrs[0]); i++) {
+         if (ptr == (void *)mapped_addrs[i]) {
+            svcControlMemory(&tmp, mapped_addrs[i], 0, size, MEMOP_FREE, 0);
+            mapped_addrs[i] = 0;
             return;
          }
       }
@@ -521,11 +545,11 @@ void deinit_vita_mmap()
    free(addr);
 }
 
-void *pl_vita_mmap(unsigned long addr, size_t size, int is_fixed,
-    enum psxMapTag tag)
+void *pl_vita_mmap(unsigned long addr, size_t size,
+    enum psxMapTag tag, int *can_retry_addr)
 {
-   (void)is_fixed;
    (void)addr;
+   *can_retry_addr = 0;
 
    psx_map_t *custom_map = custom_psx_maps;
 
index 326a40f..f349cad 100644 (file)
@@ -410,13 +410,14 @@ void plat_gvideo_close(void)
 {
 }
 
-static void *pl_emu_mmap(unsigned long addr, size_t size, int is_fixed,
-       enum psxMapTag tag)
+static void *pl_emu_mmap(unsigned long addr, size_t size,
+       enum psxMapTag tag, int *can_retry_addr)
 {
        unsigned int pbase;
        void *retval;
        int ret;
 
+       *can_retry_addr = 1;
        if (!have_warm)
                goto basic_map;
 
index 9b6faf4..21d6863 100644 (file)
@@ -873,9 +873,10 @@ void pl_start_watchdog(void)
                fprintf(stderr, "could not start watchdog: %d\n", ret);
 }
 
-static void *pl_emu_mmap(unsigned long addr, size_t size, int is_fixed,
-       enum psxMapTag tag)
+static void *pl_emu_mmap(unsigned long addr, size_t size,
+       enum psxMapTag tag, int *can_retry_addr)
 {
+       *can_retry_addr = 1;
        return plat_mmap(addr, size, 0, is_fixed);
 }
 
@@ -886,7 +887,8 @@ static void pl_emu_munmap(void *ptr, size_t size, enum psxMapTag tag)
 
 static void *pl_mmap(unsigned int size)
 {
-       return psxMapHook(0, size, 0, MAP_TAG_VRAM);
+       int can_retry_addr;
+       return psxMapHook(0, size, MAP_TAG_VRAM, &can_retry_addr);
 }
 
 static void pl_munmap(void *ptr, unsigned int size)
index 0e28b72..a70cc62 100644 (file)
 #endif
 
 static void * psxMapDefault(unsigned long addr, size_t size,
-                           int is_fixed, enum psxMapTag tag)
+                           enum psxMapTag tag, int *can_retry_addr)
 {
        void *ptr;
 #if !P_HAVE_MMAP
+       *can_retry_addr = 0;
        ptr = calloc(1, size);
        return ptr ? ptr : MAP_FAILED;
 #else
        int flags = MAP_PRIVATE | MAP_ANONYMOUS;
 
+       *can_retry_addr = 1;
        ptr = mmap((void *)(uintptr_t)addr, size,
                    PROT_READ | PROT_WRITE, flags, -1, 0);
 #ifdef MADV_HUGEPAGE
        if (size >= 2*1024*1024) {
                if (ptr != MAP_FAILED && ((uintptr_t)ptr & (2*1024*1024 - 1))) {
-                       // try to manually realign assuming bottom-to-top alloc
+                       // try to manually realign assuming decreasing addr alloc
                        munmap(ptr, size);
                        addr = (uintptr_t)ptr & ~(2*1024*1024 - 1);
                        ptr = mmap((void *)(uintptr_t)addr, size,
@@ -79,43 +81,44 @@ static void psxUnmapDefault(void *ptr, size_t size, enum psxMapTag tag)
 #endif
 }
 
-void *(*psxMapHook)(unsigned long addr, size_t size, int is_fixed,
-               enum psxMapTag tag) = psxMapDefault;
+void *(*psxMapHook)(unsigned long addr, size_t size,
+               enum psxMapTag tag, int *can_retry_addr) = psxMapDefault;
 void (*psxUnmapHook)(void *ptr, size_t size,
                     enum psxMapTag tag) = psxUnmapDefault;
 
 void *psxMap(unsigned long addr, size_t size, int is_fixed,
                enum psxMapTag tag)
 {
-       int try_ = 0;
-       unsigned long mask;
+       int try_, can_retry_addr = 0;
        void *ret;
 
-retry:
-       ret = psxMapHook(addr, size, 0, tag);
-       if (ret == NULL)
-               return MAP_FAILED;
+       for (try_ = 0; try_ < 3; try_++)
+       {
+               ret = psxMapHook(addr, size, tag, &can_retry_addr);
+               if (ret == NULL)
+                       return MAP_FAILED;
 
-       if (addr != 0 && ret != (void *)(uintptr_t)addr) {
-               SysMessage("psxMap: warning: wanted to map @%08x, got %p\n",
-                       addr, ret);
+               if (addr != 0 && ret != (void *)(uintptr_t)addr) {
+                       SysMessage("psxMap: warning: wanted to map @%08x, got %p\n",
+                               addr, ret);
+                       if (is_fixed) {
+                               psxUnmap(ret, size, tag);
+                               return MAP_FAILED;
+                       }
 
-               if (is_fixed) {
-                       psxUnmap(ret, size, tag);
-                       return MAP_FAILED;
-               }
+                       if (can_retry_addr && ((addr ^ (uintptr_t)ret) & ~0xff000000l)) {
+                               unsigned long mask;
 
-               if (((addr ^ (unsigned long)(uintptr_t)ret) & ~0xff000000l) && try_ < 2)
-               {
-                       psxUnmap(ret, size, tag);
+                               psxUnmap(ret, size, tag);
 
-                       // try to use similarly aligned memory instead
-                       // (recompiler needs this)
-                       mask = try_ ? 0xffff : 0xffffff;
-                       addr = ((uintptr_t)ret + mask) & ~mask;
-                       try_++;
-                       goto retry;
+                               // try to use similarly aligned memory instead
+                               // (recompiler prefers this)
+                               mask = try_ ? 0xffff : 0xffffff;
+                               addr = ((uintptr_t)ret + mask) & ~mask;
+                               continue;
+                       }
                }
+               break;
        }
 
        return ret;
index 9c15c03..159f575 100644 (file)
@@ -29,8 +29,8 @@ enum psxMapTag {
        MAP_TAG_LUTS,
 };
 
-extern void *(*psxMapHook)(unsigned long addr, size_t size, int is_fixed,
-       enum psxMapTag tag);
+extern void *(*psxMapHook)(unsigned long addr, size_t size,
+       enum psxMapTag tag, int *can_retry_addr);
 extern void (*psxUnmapHook)(void *ptr, size_t size, enum psxMapTag tag);
 
 void *psxMap(unsigned long addr, size_t size, int is_fixed,