+static void * psxMapDefault(unsigned long addr, size_t size,
+ int is_fixed, enum psxMapTag tag)
+{
+ void *ptr;
+#if !P_HAVE_MMAP
+ ptr = calloc(1, size);
+ return ptr ? ptr : MAP_FAILED;
+#else
+ int flags = MAP_PRIVATE | MAP_ANONYMOUS;
+
+ 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
+ munmap(ptr, size);
+ addr = (uintptr_t)ptr & ~(2*1024*1024 - 1);
+ ptr = mmap((void *)(uintptr_t)addr, size,
+ PROT_READ | PROT_WRITE, flags, -1, 0);
+ }
+ if (ptr != MAP_FAILED)
+ madvise(ptr, size, MADV_HUGEPAGE);
+ }
+#endif
+ return ptr;
+#endif
+}
+
+static void psxUnmapDefault(void *ptr, size_t size, enum psxMapTag tag)
+{
+#if !P_HAVE_MMAP
+ free(ptr);
+#else
+ munmap(ptr, size);
+#endif
+}
+
+void *(*psxMapHook)(unsigned long addr, size_t size, int is_fixed,
+ enum psxMapTag tag) = 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;
+ void *ret;
+
+retry:
+ ret = psxMapHook(addr, size, 0, tag);
+ 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 (is_fixed) {
+ psxUnmap(ret, size, tag);
+ return MAP_FAILED;
+ }
+
+ if (((addr ^ (unsigned long)(uintptr_t)ret) & ~0xff000000l) && try_ < 2)
+ {
+ 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;
+ }
+ }
+
+ return ret;
+}
+
+void psxUnmap(void *ptr, size_t size, enum psxMapTag tag)
+{
+ psxUnmapHook(ptr, size, tag);
+}
+