frontend: update libpicofe, fix missed callbacks
[pcsx_rearmed.git] / libpcsxcore / lightrec / mem.c
CommitLineData
a3c46b7f 1// SPDX-License-Identifier: LGPL-2.1-or-later
2/*
3 * Copyright (C) 2022 Paul Cercueil <paul@crapouillou.net>
4 */
5
6#ifndef _GNU_SOURCE
7#define _GNU_SOURCE
8#endif
9#include <errno.h>
10#include <fcntl.h>
11#include <inttypes.h>
12#include <stdbool.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <sys/mman.h>
16#include <sys/shm.h>
17#include <sys/stat.h>
18#include <sys/syscall.h>
19#include <unistd.h>
20
21#include "../psxhw.h"
22#include "../psxmem.h"
23#include "../r3000a.h"
24
25#include "mem.h"
26
27#define ARRAY_SIZE(a) (sizeof(a) ? (sizeof(a) / sizeof((a)[0])) : 0)
28
29#ifndef MAP_FIXED_NOREPLACE
30#define MAP_FIXED_NOREPLACE 0x100000
31#endif
32
33#ifndef MFD_HUGETLB
34#define MFD_HUGETLB 0x0004
35#endif
36
37static const uintptr_t supported_io_bases[] = {
38 0x0,
39 0x10000000,
40 0x40000000,
41 0x80000000,
42};
43
44static void * mmap_huge(void *addr, size_t length, int prot, int flags,
45 int fd, off_t offset)
46{
47 void *map = MAP_FAILED;
48
49 if (length >= 0x200000) {
50 map = mmap(addr, length, prot,
51 flags | MAP_HUGETLB | (21 << MAP_HUGE_SHIFT),
52 fd, offset);
53 if (map != MAP_FAILED)
54 printf("Hugetlb mmap to address 0x%" PRIxPTR " succeeded\n",
55 (uintptr_t) addr);
56 }
57
58 if (map == MAP_FAILED) {
59 map = mmap(addr, length, prot, flags, fd, offset);
60 if (map != MAP_FAILED) {
61 printf("Regular mmap to address 0x%" PRIxPTR " succeeded\n",
62 (uintptr_t) addr);
63#ifdef MADV_HUGEPAGE
64 madvise(map, length, MADV_HUGEPAGE);
65#endif
66 }
67 }
68
69 return map;
70}
71
72static int lightrec_mmap_ram(bool hugetlb)
73{
74 unsigned int i, j;
75 int err, memfd, flags = 0;
76 uintptr_t base;
77 void *map;
78
79 if (hugetlb)
80 flags |= MFD_HUGETLB;
81
82 memfd = syscall(SYS_memfd_create, "/lightrec_memfd",
83 flags);
84 if (memfd < 0) {
5dd884df 85 SysMessage("Failed to create memfd: %d", errno);
a3c46b7f 86 err = -errno;
a3c46b7f 87 return err;
88 }
89
90 err = ftruncate(memfd, 0x200000);
91 if (err < 0) {
5dd884df 92 SysMessage("Could not trim memfd: %d", errno);
a3c46b7f 93 err = -errno;
a3c46b7f 94 goto err_close_memfd;
95 }
96
97 for (i = 0; i < ARRAY_SIZE(supported_io_bases); i++) {
98 base = supported_io_bases[i];
99
100 for (j = 0; j < 4; j++) {
101 void *base_ptr = (void *)(base + j * 0x200000);
102 map = mmap_huge(base_ptr, 0x200000, PROT_READ | PROT_WRITE,
103 MAP_SHARED | MAP_FIXED_NOREPLACE, memfd, 0);
104 if (map == MAP_FAILED)
105 break;
106 // some systems ignore MAP_FIXED_NOREPLACE
107 if (map != base_ptr) {
108 munmap(map, 0x200000);
109 break;
110 }
111 }
112
113 /* Impossible to map using this base */
114 if (j == 0)
115 continue;
116
117 /* All mirrors mapped - we got a match! */
118 if (j == 4)
119 break;
120
121 /* Only some mirrors mapped - clean the mess and try again */
122 for (; j > 0; j--)
123 munmap((void *)(base + (j - 1) * 0x200000), 0x200000);
124 }
125
126 if (i == ARRAY_SIZE(supported_io_bases)) {
127 err = -EINVAL;
128 goto err_close_memfd;
129 }
130
131 err = 0;
132 psxM = (s8 *)base;
133
134err_close_memfd:
135 close(memfd);
136 return err;
137}
138
139int lightrec_init_mmap(void)
140{
141 unsigned int i;
5dd884df 142 s8 *base, *target;
a3c46b7f 143 void *map;
144 int err = lightrec_mmap_ram(true);
145 if (err) {
146 err = lightrec_mmap_ram(false);
147 if (err) {
5dd884df 148 SysMessage("Unable to mmap RAM and mirrors");
a3c46b7f 149 return err;
150 }
151 }
152
5dd884df 153 base = psxM;
a3c46b7f 154
5dd884df 155 target = base + 0x1f000000;
156 map = mmap(target, 0x10000,
a3c46b7f 157 PROT_READ | PROT_WRITE,
5dd884df 158 MAP_PRIVATE | /*MAP_FIXED_NOREPLACE |*/ MAP_ANONYMOUS, -1, 0);
a3c46b7f 159 if (map == MAP_FAILED) {
5dd884df 160 SysMessage("Unable to mmap parallel port: %d", errno);
a3c46b7f 161 err = -EINVAL;
a3c46b7f 162 goto err_unmap;
163 }
5dd884df 164 if (map != target)
165 SysMessage("lightrec: mapped parallel port at %p, wanted %p", map, target);
a3c46b7f 166
167 psxP = (s8 *)map;
168
5dd884df 169 target = base + 0x1fc00000;
170 map = mmap_huge(target, 0x200000,
a3c46b7f 171 PROT_READ | PROT_WRITE,
5dd884df 172 MAP_PRIVATE | /*MAP_FIXED_NOREPLACE |*/ MAP_ANONYMOUS, -1, 0);
a3c46b7f 173 if (map == MAP_FAILED) {
5dd884df 174 SysMessage("Unable to mmap BIOS: %d", errno);
a3c46b7f 175 err = -EINVAL;
a3c46b7f 176 goto err_unmap_parallel;
177 }
5dd884df 178 if (map != target)
179 SysMessage("lightrec: mapped bios at %p, wanted %p", map, target);
a3c46b7f 180
181 psxR = (s8 *)map;
182
5dd884df 183 target = base + 0x1f800000;
184 map = mmap(target, 0x10000,
a3c46b7f 185 PROT_READ | PROT_WRITE,
5dd884df 186 MAP_PRIVATE | /*MAP_FIXED_NOREPLACE |*/ MAP_ANONYMOUS, 0, 0);
a3c46b7f 187 if (map == MAP_FAILED) {
5dd884df 188 SysMessage("Unable to mmap scratchpad: %d", errno);
a3c46b7f 189 err = -EINVAL;
a3c46b7f 190 goto err_unmap_bios;
191 }
5dd884df 192 if (map != target)
193 SysMessage("lightrec: mapped scratchpad at %p, wanted %p", map, target);
a3c46b7f 194
195 psxH = (s8 *)map;
196
5dd884df 197 target = base + 0x800000;
198 map = mmap_huge(target, CODE_BUFFER_SIZE,
a3c46b7f 199 PROT_EXEC | PROT_READ | PROT_WRITE,
5dd884df 200 MAP_PRIVATE | /*MAP_FIXED_NOREPLACE |*/ MAP_ANONYMOUS,
a3c46b7f 201 -1, 0);
202 if (map == MAP_FAILED) {
5dd884df 203 SysMessage("Unable to mmap code buffer: %d", errno);
a3c46b7f 204 err = -EINVAL;
a3c46b7f 205 goto err_unmap_scratch;
206 }
5dd884df 207 if (map != target)
208 SysMessage("lightrec: mapped code at %p, wanted %p", map, target);
a3c46b7f 209
210 code_buffer = map;
211
212 return 0;
213
214err_unmap_scratch:
215 munmap(psxH, 0x10000);
216err_unmap_bios:
217 munmap(psxR, 0x200000);
218err_unmap_parallel:
219 munmap(psxP, 0x10000);
220err_unmap:
221 for (i = 0; i < 4; i++)
222 munmap((void *)((uintptr_t)psxM + i * 0x200000), 0x200000);
223 return err;
224}
225
226void lightrec_free_mmap(void)
227{
228 unsigned int i;
229
230 munmap(code_buffer, CODE_BUFFER_SIZE);
231 munmap(psxH, 0x10000);
232 munmap(psxR, 0x200000);
233 munmap(psxP, 0x10000);
234 for (i = 0; i < 4; i++)
235 munmap((void *)((uintptr_t)psxM + i * 0x200000), 0x200000);
236}