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