psxinterpreter: log reserved insn once
[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
a093e81f
PC
34static const uintptr_t supported_io_bases[] = {
35 0x0,
36 0x10000000,
37 0x40000000,
38 0x80000000,
39};
40
41static void * mmap_huge(void *addr, size_t length, int prot, int flags,
42 int fd, off_t offset)
43{
44 void *map = MAP_FAILED;
45
46 if (length >= 0x200000) {
47 map = mmap(addr, length, prot,
48 flags | MAP_HUGETLB | (21 << MAP_HUGE_SHIFT),
49 fd, offset);
50 if (map != MAP_FAILED)
51 printf("Hugetlb mmap to address 0x%lx succeeded\n", (uintptr_t) addr);
52 }
53
54 if (map == MAP_FAILED) {
55 map = mmap(addr, length, prot, flags, fd, offset);
56 if (map != MAP_FAILED)
57 printf("Regular mmap to address 0x%lx succeeded\n", (uintptr_t) addr);
58 }
59
60 return map;
61}
62
63static int lightrec_mmap_ram(bool hugetlb)
64{
65 unsigned int i, j;
66 int err, memfd, flags = 0;
67 uintptr_t base;
68 void *map;
69
70 if (hugetlb)
71 flags |= MFD_HUGETLB;
72
e5794429 73 memfd = syscall(SYS_memfd_create, "/lightrec_memfd",
74 flags);
a093e81f
PC
75 if (memfd < 0) {
76 err = -errno;
77 fprintf(stderr, "Failed to create memfd: %d\n", err);
78 return err;
79 }
80
81 err = ftruncate(memfd, 0x200000);
82 if (err < 0) {
83 err = -errno;
84 fprintf(stderr, "Could not trim memfd: %d\n", err);
85 goto err_close_memfd;
86 }
87
88 for (i = 0; i < ARRAY_SIZE(supported_io_bases); i++) {
89 base = supported_io_bases[i];
90
91 for (j = 0; j < 4; j++) {
92 map = mmap_huge((void *)(base + j * 0x200000),
93 0x200000, PROT_READ | PROT_WRITE,
94 MAP_SHARED | MAP_FIXED, memfd, 0);
95 if (map == MAP_FAILED)
96 break;
97 }
98
99 /* Impossible to map using this base */
100 if (j == 0)
101 continue;
102
103 /* All mirrors mapped - we got a match! */
104 if (j == 4)
105 break;
106
107 /* Only some mirrors mapped - clean the mess and try again */
108 for (; j > 0; j--)
109 munmap((void *)(base + (j - 1) * 0x200000), 0x200000);
110 }
111
112 if (i == ARRAY_SIZE(supported_io_bases)) {
113 err = -EINVAL;
114 goto err_close_memfd;
115 }
116
117 err = 0;
118 psxM = (s8 *)base;
119
120err_close_memfd:
121 close(memfd);
122 return err;
123}
124
125int lightrec_init_mmap(void)
126{
127 unsigned int i;
128 uintptr_t base;
129 void *map;
e5794429 130 int err = lightrec_mmap_ram(true);
a093e81f
PC
131 if (err) {
132 err = lightrec_mmap_ram(false);
133 if (err) {
134 fprintf(stderr, "Unable to mmap RAM and mirrors\n");
135 return err;
136 }
137 }
138
139 base = (uintptr_t) psxM;
140
141 map = mmap((void *)(base + 0x1f000000), 0x10000,
142 PROT_READ | PROT_WRITE,
143 MAP_PRIVATE | MAP_FIXED_NOREPLACE | MAP_ANONYMOUS, 0, 0);
144 if (map == MAP_FAILED) {
145 err = -EINVAL;
146 fprintf(stderr, "Unable to mmap parallel port\n");
147 goto err_unmap;
148 }
149
150 psxP = (s8 *)map;
151
152 map = mmap_huge((void *)(base + 0x1fc00000), 0x200000,
153 PROT_READ | PROT_WRITE,
154 MAP_PRIVATE | MAP_FIXED_NOREPLACE | MAP_ANONYMOUS, 0, 0);
155 if (map == MAP_FAILED) {
156 err = -EINVAL;
157 fprintf(stderr, "Unable to mmap BIOS\n");
158 goto err_unmap_parallel;
159 }
160
161 psxR = (s8 *)map;
162
163 map = mmap((void *)(base + 0x1f800000), 0x10000,
164 PROT_READ | PROT_WRITE,
165 MAP_PRIVATE | MAP_FIXED_NOREPLACE | MAP_ANONYMOUS, 0, 0);
166 if (map == MAP_FAILED) {
167 err = -EINVAL;
168 fprintf(stderr, "Unable to mmap scratchpad\n");
169 goto err_unmap_bios;
170 }
171
172 psxH = (s8 *)map;
173
f8548105
PC
174 map = mmap_huge((void *)(base + 0x800000), CODE_BUFFER_SIZE,
175 PROT_EXEC | PROT_READ | PROT_WRITE,
176 MAP_PRIVATE | MAP_FIXED_NOREPLACE | MAP_ANONYMOUS,
177 0, 0);
178 if (map == MAP_FAILED) {
179 err = -EINVAL;
180 fprintf(stderr, "Unable to mmap code buffer\n");
181 goto err_unmap_scratch;
182 }
183
184 code_buffer = map;
185
a093e81f
PC
186 return 0;
187
f8548105
PC
188err_unmap_scratch:
189 munmap(psxH, 0x10000);
a093e81f 190err_unmap_bios:
14a530af 191 munmap(psxR, 0x200000);
a093e81f
PC
192err_unmap_parallel:
193 munmap(psxP, 0x10000);
194err_unmap:
195 for (i = 0; i < 4; i++)
196 munmap((void *)((uintptr_t)psxM + i * 0x200000), 0x200000);
197 return err;
198}
199
200void lightrec_free_mmap(void)
201{
202 unsigned int i;
203
f8548105 204 munmap(code_buffer, CODE_BUFFER_SIZE);
a093e81f 205 munmap(psxH, 0x10000);
14a530af 206 munmap(psxR, 0x200000);
a093e81f
PC
207 munmap(psxP, 0x10000);
208 for (i = 0; i < 4; i++)
209 munmap((void *)((uintptr_t)psxM + i * 0x200000), 0x200000);
210}