From 4284a818154d82c5a1f762c6bb83722299ab7177 Mon Sep 17 00:00:00 2001 From: notaz Date: Mon, 30 Sep 2024 21:14:41 +0300 Subject: [PATCH] new 3ds_mmap, avoid useless retries --- frontend/libretro.c | 126 +++++++++++++++++++++++---------------- frontend/plat_pollux.c | 5 +- frontend/plugin_lib.c | 8 ++- libpcsxcore/psxmem.c | 55 +++++++++-------- libpcsxcore/psxmem_map.h | 4 +- 5 files changed, 114 insertions(+), 84 deletions(-) diff --git a/frontend/libretro.c b/frontend/libretro.c index 90f40a62..dd45d168 100644 --- a/frontend/libretro.c +++ b/frontend/libretro.c @@ -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; diff --git a/frontend/plat_pollux.c b/frontend/plat_pollux.c index 326a40f1..f349cad1 100644 --- a/frontend/plat_pollux.c +++ b/frontend/plat_pollux.c @@ -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; diff --git a/frontend/plugin_lib.c b/frontend/plugin_lib.c index 9b6faf44..21d6863d 100644 --- a/frontend/plugin_lib.c +++ b/frontend/plugin_lib.c @@ -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) diff --git a/libpcsxcore/psxmem.c b/libpcsxcore/psxmem.c index 0e28b72c..a70cc623 100644 --- a/libpcsxcore/psxmem.c +++ b/libpcsxcore/psxmem.c @@ -42,21 +42,23 @@ #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; diff --git a/libpcsxcore/psxmem_map.h b/libpcsxcore/psxmem_map.h index 9c15c035..159f5751 100644 --- a/libpcsxcore/psxmem_map.h +++ b/libpcsxcore/psxmem_map.h @@ -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, -- 2.39.5