lightrec: Add new memory init functions
[pcsx_rearmed.git] / libpcsxcore / lightrec / mem.c
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
28 static const uintptr_t supported_io_bases[] = {
29         0x0,
30         0x10000000,
31         0x40000000,
32         0x80000000,
33 };
34
35 static 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
57 static 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
113 err_close_memfd:
114         close(memfd);
115         return err;
116 }
117
118 int 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
171 err_unmap_bios:
172         munmap(psxR, 0x80000);
173 err_unmap_parallel:
174         munmap(psxP, 0x10000);
175 err_unmap:
176         for (i = 0; i < 4; i++)
177                 munmap((void *)((uintptr_t)psxM + i * 0x200000), 0x200000);
178         return err;
179 }
180
181 void 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 }