blob: 4d756eab445c74a0674d3c53de0efe8485b35cf5 [file] [log] [blame]
Nico Huberf03ef4f2017-03-04 13:57:09 +01001/*
2 * Copyright (C) 2017 Nico Huber <nico.h@gmx.de>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include <stdint.h>
16#include <sys/mman.h>
17#include <unistd.h>
18#include <fcntl.h>
19#include <errno.h>
20
21#define HW_FILE_READ 0x01
22#define HW_FILE_WRITE 0x02
23
24static int map_file(const char *const path,
25 const uint64_t addr,
26 const uint32_t len,
27 const uint32_t mode)
28{
29 const int prot = (mode & HW_FILE_READ ? PROT_READ : 0) |
30 (mode & HW_FILE_WRITE ? PROT_WRITE : 0);
31
32 if (mode & ~(HW_FILE_READ | HW_FILE_WRITE) ||
33 !(mode & (HW_FILE_READ | HW_FILE_WRITE)))
34 return EINVAL;
35
36 const int fd = open(path, mode & HW_FILE_WRITE ? O_RDWR : O_RDONLY);
37 if (fd < 0)
38 return errno;
39
40 void *const mapped = mmap((void *)(uintptr_t)addr, len, prot,
41 MAP_SHARED | MAP_FIXED, fd, (off_t)0);
42 close(fd);
43 if (mapped == MAP_FAILED)
44 return errno;
45
46 return 0;
47}
48
49static int map_fill_from_file(const char *const path,
50 const uint64_t addr,
51 const uint32_t len,
52 const uint32_t mode)
53{
54 uint32_t xferred;
55 ssize_t read_ret;
56
57 if (mode != HW_FILE_READ)
58 return EINVAL;
59
60 void *const mapped = mmap((void *)(uintptr_t)addr, len,
61 PROT_READ | PROT_WRITE,
62 MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED,
63 -1, (off_t)0);
64 if (mapped == MAP_FAILED)
65 return errno;
66
67 const int fd = open(path, O_RDONLY);
68 if (fd < 0)
69 goto _munmap;
70
71 xferred = 0;
72 do {
73 read_ret = read(fd, (uint8_t *)mapped + xferred, len - xferred);
74 if (read_ret > 0)
75 xferred += read_ret;
76 } while ((read_ret > 0 || (read_ret == -1 && errno == EINTR))
77 && xferred < len);
78 close(fd);
79
80 if (xferred < len)
81 goto _munmap;
82
83 if (mprotect(mapped, len, PROT_READ))
84 goto _munmap;
85
86 return 0;
87
88_munmap:
89 munmap(mapped, len);
90 return errno;
91}
92
93int hw_file_map(const char *const path,
94 const uint64_t addr,
95 const uint32_t len,
96 const uint32_t mode,
97 const int copy)
98{
99 if (copy)
100 return map_fill_from_file(path, addr, len, mode);
101 else
102 return map_file(path, addr, len, mode);
103}