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