blob: 66bbd5ddada53f40dd5b38b859227bc4a724c153 [file] [log] [blame]
Amit Pundird477f822020-02-07 22:26:08 +05301#include <sys/mman.h>
2#include <sys/stat.h>
3#include <sys/types.h>
4#include <dirent.h>
5#include <errno.h>
6#include <fcntl.h>
7#ifndef ANDROID
8#include <libudev.h>
9#else
10#include <sys/endian.h>
11#endif
12#include <stdbool.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <limits.h>
16#include <string.h>
17#include <unistd.h>
18#include "rmtfs.h"
19
20static int rmtfs_mem_enumerate(struct rmtfs_mem *rmem);
21
22struct rmtfs_mem {
23 uint64_t address;
24 uint64_t size;
25 void *base;
26 int fd;
27};
28
29#ifndef ANDROID
30
31static int parse_hex_sysattr(struct udev_device *dev, const char *name,
32 uint64_t *value)
33{
34 unsigned long long val;
35 const char *buf;
36 char *endptr;
37
38 buf = udev_device_get_sysattr_value(dev, name);
39 if (!buf)
40 return -ENOENT;
41
42 errno = 0;
43 val = strtoull(buf, &endptr, 16);
44 if ((val == ULLONG_MAX && errno == ERANGE) || endptr == buf) {
45 return -errno;
46 }
47
48 *value = val;
49
50 return 0;
51}
52
53static int rmtfs_mem_open_rfsa(struct rmtfs_mem *rmem, int client_id)
54{
55 struct udev_device *dev;
56 struct udev *udev;
57 int saved_errno;
58 struct stat sb;
59 char path[32];
60 int ret;
61 int fd;
62
63 sprintf(path, "/dev/qcom_rmtfs_mem%d", client_id);
64
65 fd = open(path, O_RDWR);
66 if (fd < 0) {
67 saved_errno = errno;
68 fprintf(stderr, "failed to open %s: %s\n", path, strerror(errno));
69 return -saved_errno;
70 }
71 rmem->fd = fd;
72
73 ret = fstat(fd, &sb);
74 if (ret < 0) {
75 saved_errno = errno;
76 fprintf(stderr, "failed to stat %s: %s\n", path, strerror(errno));
77 close(fd);
78 goto err_close_fd;
79 }
80
81 udev = udev_new();
82 if (!udev) {
83 saved_errno = errno;
84 fprintf(stderr, "failed to create udev context\n");
85 goto err_close_fd;
86 }
87
88 dev = udev_device_new_from_devnum(udev, 'c', sb.st_rdev);
89 if (!dev) {
90 saved_errno = errno;
91 fprintf(stderr, "unable to find udev device\n");
92 goto err_unref_udev;
93 }
94
95 ret = parse_hex_sysattr(dev, "phys_addr", &rmem->address);
96 if (ret < 0) {
97 fprintf(stderr, "failed to parse phys_addr of %s\n", path);
98 saved_errno = -ret;
99 goto err_unref_dev;
100 }
101
102 ret = parse_hex_sysattr(dev, "size", &rmem->size);
103 if (ret < 0) {
104 fprintf(stderr, "failed to parse size of %s\n", path);
105 saved_errno = -ret;
106 goto err_unref_dev;
107 }
108
109 udev_device_unref(dev);
110 udev_unref(udev);
111
112 return 0;
113
114err_unref_dev:
115 udev_device_unref(dev);
116err_unref_udev:
117 udev_unref(udev);
118err_close_fd:
119 close(fd);
120 return -saved_errno;
121}
122
123static int rmtfs_mem_open_uio(struct rmtfs_mem *rmem, int client_id)
124{
125 struct udev_device *dev;
126 struct udev *udev;
127 int saved_errno;
128 struct stat sb;
129 char path[32];
130 int ret;
131 int fd;
132
133 snprintf(path, sizeof(path), "/dev/qcom_rmtfs_uio%d", client_id);
134
135 fd = open(path, O_RDWR);
136 if (fd < 0) {
137 saved_errno = errno;
138 fprintf(stderr, "failed to open %s: %s\n", path, strerror(errno));
139 return -saved_errno;
140 }
141 rmem->fd = fd;
142
143 ret = fstat(fd, &sb);
144 if (ret < 0) {
145 saved_errno = errno;
146 fprintf(stderr, "failed to stat %s: %s\n", path, strerror(errno));
147 close(fd);
148 goto err_close_fd;
149 }
150
151 udev = udev_new();
152 if (!udev) {
153 saved_errno = errno;
154 fprintf(stderr, "failed to create udev context\n");
155 goto err_close_fd;
156 }
157
158 dev = udev_device_new_from_devnum(udev, 'c', sb.st_rdev);
159 if (!dev) {
160 saved_errno = errno;
161 fprintf(stderr, "unable to find udev device\n");
162 goto err_unref_udev;
163 }
164
165 ret = parse_hex_sysattr(dev, "maps/map0/addr", &rmem->address);
166 if (ret < 0) {
167 fprintf(stderr, "failed to parse phys_addr of %s\n", path);
168 saved_errno = -ret;
169 goto err_unref_dev;
170 }
171
172 ret = parse_hex_sysattr(dev, "maps/map0/size", &rmem->size);
173 if (ret < 0) {
174 fprintf(stderr, "failed to parse size of %s\n", path);
175 saved_errno = -ret;
176 goto err_unref_dev;
177 }
178
179 rmem->base = mmap(0, rmem->size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
180 if (rmem->base == MAP_FAILED) {
181 saved_errno = errno;
182 fprintf(stderr, "failed to mmap: %s\n", strerror(errno));
183 goto err_unref_dev;
184 }
185
186 udev_device_unref(dev);
187 udev_unref(udev);
188
189 return 0;
190
191err_unref_dev:
192 udev_device_unref(dev);
193err_unref_udev:
194 udev_unref(udev);
195err_close_fd:
196 close(fd);
197 return -saved_errno;
198}
199
200#else
201
202#define PAGE_SIZE 4096
203
204static int rmtfs_mem_open_rfsa(struct rmtfs_mem *rmem, int client_id)
205{
206 int saved_errno;
207 int fd;
208 char path[PATH_MAX];
209 char val[PAGE_SIZE];
210 char *endptr;
211
212 errno = 0;
213
214 snprintf(path, sizeof(path), "/sys/class/rmtfs/qcom_rmtfs_mem%d/phys_addr", client_id);
215 fd = open(path, O_RDONLY);
216 if (fd < 0) {
217 saved_errno = errno;
218 fprintf(stderr, "failed to open %s: %s\n", path, strerror(errno));
219 return -saved_errno;
220 }
221 read(fd, val, sizeof(val));
222 rmem->address = strtoull(val, &endptr, 16);
223 if ((rmem->address == ULLONG_MAX && errno == ERANGE) || endptr == val) {
224 saved_errno = errno;
225 goto err_close_fd;
226 }
227 close(fd);
228
229 snprintf(path, sizeof(path), "/sys/class/rmtfs/qcom_rmtfs_mem%d/size", client_id);
230 fd = open(path, O_RDONLY);
231 if (fd < 0) {
232 saved_errno = errno;
233 fprintf(stderr, "failed to open %s: %s\n", path, strerror(errno));
234 return -saved_errno;
235 }
236 read(fd, val, sizeof(val));
237 rmem->size = strtoull(val, &endptr, 16);
238 if ((rmem->size == ULLONG_MAX && errno == ERANGE) || endptr == val) {
239 saved_errno = errno;
240 goto err_close_fd;
241 }
242 close(fd);
243
244 return 0;
245
246err_close_fd:
247 close(fd);
248 return -saved_errno;
249}
250
251static int rmtfs_mem_open_uio(struct rmtfs_mem *rmem, int client_id)
252{
253 fprintf(stderr, "uio access is not supported on ANDROID yet\n");
254 return -EINVAL;
255}
256
257#endif
258
259struct rmtfs_mem *rmtfs_mem_open(void)
260{
261 struct rmtfs_mem *rmem;
262 void *base;
263 int ret;
264 int fd;
265
266 rmem = malloc(sizeof(*rmem));
267 if (!rmem)
268 return NULL;
269
270 memset(rmem, 0, sizeof(*rmem));
271
272 ret = rmtfs_mem_open_rfsa(rmem, 1);
273 if (ret < 0 && ret != -ENOENT) {
274 goto err;
275 } else if (ret < 0) {
276 fprintf(stderr, "falling back to uio access\n");
277 ret = rmtfs_mem_open_uio(rmem, 1);
278 if (ret < 0 && ret != -ENOENT) {
279 goto err;
280 } else if (ret < 0) {
281 fprintf(stderr, "falling back to /dev/mem access\n");
282
283 ret = rmtfs_mem_enumerate(rmem);
284 if (ret < 0)
285 goto err;
286
287 fd = open("/dev/mem", O_RDWR|O_SYNC);
288 if (fd < 0) {
289 fprintf(stderr, "failed to open /dev/mem\n");
290 goto err;
291 }
292
293 base = mmap(0, rmem->size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, rmem->address);
294 if (base == MAP_FAILED) {
295 fprintf(stderr, "failed to mmap: %s\n", strerror(errno));
296 goto err_close_fd;
297 }
298
299 rmem->base = base;
300 rmem->fd = fd;
301 }
302 }
303
304 return rmem;
305
306err_close_fd:
307 close(fd);
308err:
309 free(rmem);
310 return NULL;
311}
312
313int64_t rmtfs_mem_alloc(struct rmtfs_mem *rmem, size_t alloc_size)
314{
315 if (alloc_size > rmem->size) {
316 fprintf(stderr,
317 "[RMTFS] rmtfs shared memory not large enough for allocation request 0x%zx vs 0x%lx\n",
318 alloc_size, rmem->size);
319 return -EINVAL;
320 }
321
322 return rmem->address;
323}
324
325void rmtfs_mem_free(struct rmtfs_mem *rmem)
326{
327}
328
329static void *rmtfs_mem_ptr(struct rmtfs_mem *rmem, unsigned long phys_address, ssize_t len)
330{
331 uint64_t start;
332 uint64_t end;
333
334 if (len < 0)
335 return NULL;
336
337 start = phys_address;
338 end = start + len;
339
340 if (start < rmem->address || end > rmem->address + rmem->size)
341 return NULL;
342
343 return rmem->base + phys_address - rmem->address;
344}
345
346ssize_t rmtfs_mem_read(struct rmtfs_mem *rmem, unsigned long phys_address, void *buf, ssize_t len)
347{
348 off_t offset;
349 void *ptr;
350
351 if (rmem->base) {
352 ptr = rmtfs_mem_ptr(rmem, phys_address, len);
353 if (!ptr)
354 return -EINVAL;
355
356 memcpy(buf, ptr, len);
357 } else {
358 offset = phys_address - rmem->address;
359 len = pread(rmem->fd, buf, len, offset);
360 }
361
362 return len;
363}
364
365ssize_t rmtfs_mem_write(struct rmtfs_mem *rmem, unsigned long phys_address, const void *buf, ssize_t len)
366{
367 off_t offset;
368 void *ptr;
369
370 if (rmem->base) {
371 ptr = rmtfs_mem_ptr(rmem, phys_address, len);
372 if (!ptr)
373 return -EINVAL;
374
375 memcpy(ptr, buf, len);
376 } else {
377 offset = phys_address - rmem->address;
378 len = pwrite(rmem->fd, buf, len, offset);
379 }
380
381 return len;
382}
383
384void rmtfs_mem_close(struct rmtfs_mem *rmem)
385{
386 if (rmem->base)
387 munmap(rmem->base, rmem->size);
388
389 close(rmem->fd);
390
391 free(rmem);
392}
393
394static int rmtfs_mem_enumerate(struct rmtfs_mem *rmem)
395{
396 union {
397 uint32_t dw[2];
398 uint64_t qw[2];
399 } reg;
400 struct dirent *de;
401 int basefd;
402 int dirfd;
403 int regfd;
404 DIR *dir;
405 int ret = 0;
406 int n;
407
408 basefd = open("/proc/device-tree/reserved-memory/", O_DIRECTORY);
409 dir = fdopendir(basefd);
410 if (!dir) {
411 fprintf(stderr,
412 "Unable to open reserved-memory device tree node: %s\n",
413 strerror(-errno));
414 close(basefd);
415 return -1;
416 }
417
418 while ((de = readdir(dir)) != NULL) {
419 if (strncmp(de->d_name, "rmtfs", 5) != 0)
420 continue;
421
422 dirfd = openat(basefd, de->d_name, O_DIRECTORY);
423 if (dirfd < 0) {
424 fprintf(stderr, "failed to open %s: %s\n",
425 de->d_name, strerror(-errno));
426 ret = -1;
427 goto out;
428 }
429
430 regfd = openat(dirfd, "reg", O_RDONLY);
431 if (regfd < 0) {
432 fprintf(stderr, "failed to open reg of %s: %s\n",
433 de->d_name, strerror(-errno));
434 ret = -1;
435 goto out;
436 }
437
438 n = read(regfd, &reg, sizeof(reg));
439 if (n == 2 * sizeof(uint32_t)) {
440 rmem->address = be32toh(reg.dw[0]);
441 rmem->size = be32toh(reg.dw[1]);
442 } else if (n == 2 * sizeof(uint64_t)) {
443 rmem->address = be64toh(reg.qw[0]);
444 rmem->size = be64toh(reg.qw[1]);
445 } else {
446 fprintf(stderr, "failed to read reg of %s: %s\n",
447 de->d_name, strerror(-errno));
448 ret = -1;
449 }
450
451 close(regfd);
452 close(dirfd);
453 break;
454 }
455
456out:
457 closedir(dir);
458 close(basefd);
459 return ret;
460}