1 // SPDX-License-Identifier: LGPL-2.1-or-later
3 * Copyright (C) 2022 Paul Cercueil <paul@crapouillou.net>
17 #include <sys/syscall.h>
21 #include "../psxmem.h"
22 #include "../r3000a.h"
26 #define ARRAY_SIZE(a) (sizeof(a) ? (sizeof(a) / sizeof((a)[0])) : 0)
28 #ifndef MAP_FIXED_NOREPLACE
29 #define MAP_FIXED_NOREPLACE 0x100000
33 #define MFD_HUGETLB 0x0004
36 static const uintptr_t supported_io_bases[] = {
43 static void * mmap_huge(void *addr, size_t length, int prot, int flags,
46 void *map = MAP_FAILED;
48 if (length >= 0x200000) {
49 map = mmap(addr, length, prot,
50 flags | MAP_HUGETLB | (21 << MAP_HUGE_SHIFT),
52 if (map != MAP_FAILED)
53 printf("Hugetlb mmap to address 0x%lx succeeded\n", (uintptr_t) addr);
56 if (map == MAP_FAILED) {
57 map = mmap(addr, length, prot, flags, fd, offset);
58 if (map != MAP_FAILED) {
59 printf("Regular mmap to address 0x%lx succeeded\n", (uintptr_t) addr);
61 madvise(map, length, MADV_HUGEPAGE);
69 static int lightrec_mmap_ram(bool hugetlb)
72 int err, memfd, flags = 0;
79 memfd = syscall(SYS_memfd_create, "/lightrec_memfd",
83 fprintf(stderr, "Failed to create memfd: %d\n", err);
87 err = ftruncate(memfd, 0x200000);
90 fprintf(stderr, "Could not trim memfd: %d\n", err);
94 for (i = 0; i < ARRAY_SIZE(supported_io_bases); i++) {
95 base = supported_io_bases[i];
97 for (j = 0; j < 4; j++) {
98 void *base_ptr = (void *)(base + j * 0x200000);
99 map = mmap_huge(base_ptr, 0x200000, PROT_READ | PROT_WRITE,
100 MAP_SHARED | MAP_FIXED_NOREPLACE, memfd, 0);
101 if (map == MAP_FAILED)
103 // some systems ignore MAP_FIXED_NOREPLACE
104 if (map != base_ptr) {
105 munmap(map, 0x200000);
110 /* Impossible to map using this base */
114 /* All mirrors mapped - we got a match! */
118 /* Only some mirrors mapped - clean the mess and try again */
120 munmap((void *)(base + (j - 1) * 0x200000), 0x200000);
123 if (i == ARRAY_SIZE(supported_io_bases)) {
125 goto err_close_memfd;
136 int lightrec_init_mmap(void)
141 int err = lightrec_mmap_ram(true);
143 err = lightrec_mmap_ram(false);
145 fprintf(stderr, "Unable to mmap RAM and mirrors\n");
150 base = (uintptr_t) psxM;
152 map = mmap((void *)(base + 0x1f000000), 0x10000,
153 PROT_READ | PROT_WRITE,
154 MAP_PRIVATE | MAP_FIXED_NOREPLACE | MAP_ANONYMOUS, -1, 0);
155 if (map == MAP_FAILED) {
157 fprintf(stderr, "Unable to mmap parallel port\n");
163 map = mmap_huge((void *)(base + 0x1fc00000), 0x200000,
164 PROT_READ | PROT_WRITE,
165 MAP_PRIVATE | MAP_FIXED_NOREPLACE | MAP_ANONYMOUS, -1, 0);
166 if (map == MAP_FAILED) {
168 fprintf(stderr, "Unable to mmap BIOS\n");
169 goto err_unmap_parallel;
174 map = mmap((void *)(base + 0x1f800000), 0x10000,
175 PROT_READ | PROT_WRITE,
176 MAP_PRIVATE | MAP_FIXED_NOREPLACE | MAP_ANONYMOUS, 0, 0);
177 if (map == MAP_FAILED) {
179 fprintf(stderr, "Unable to mmap scratchpad\n");
185 map = mmap_huge((void *)(base + 0x800000), CODE_BUFFER_SIZE,
186 PROT_EXEC | PROT_READ | PROT_WRITE,
187 MAP_PRIVATE | MAP_FIXED_NOREPLACE | MAP_ANONYMOUS,
189 if (map == MAP_FAILED) {
191 fprintf(stderr, "Unable to mmap code buffer\n");
192 goto err_unmap_scratch;
200 munmap(psxH, 0x10000);
202 munmap(psxR, 0x200000);
204 munmap(psxP, 0x10000);
206 for (i = 0; i < 4; i++)
207 munmap((void *)((uintptr_t)psxM + i * 0x200000), 0x200000);
211 void lightrec_free_mmap(void)
215 munmap(code_buffer, CODE_BUFFER_SIZE);
216 munmap(psxH, 0x10000);
217 munmap(psxR, 0x200000);
218 munmap(psxP, 0x10000);
219 for (i = 0; i < 4; i++)
220 munmap((void *)((uintptr_t)psxM + i * 0x200000), 0x200000);