blob: 7a9478d82928d9a8784263b18a980d461276c3ac [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
Nico Hubera43b1ee2017-07-09 15:40:25 +020024static int map_file(uint64_t *const addr,
25 const char *const path,
Nico Huberf03ef4f2017-03-04 13:57:09 +010026 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
Nico Hubera43b1ee2017-07-09 15:40:25 +020040 void *const mapped = mmap(NULL, len, prot, MAP_SHARED, fd, (off_t)0);
Nico Huberf03ef4f2017-03-04 13:57:09 +010041 close(fd);
42 if (mapped == MAP_FAILED)
43 return errno;
44
Nico Hubera43b1ee2017-07-09 15:40:25 +020045 *addr = (uint64_t)(uintptr_t)mapped;
Nico Huberf03ef4f2017-03-04 13:57:09 +010046 return 0;
47}
48
Nico Hubera43b1ee2017-07-09 15:40:25 +020049static int map_fill_from_file(uint64_t *const addr,
50 const char *const path,
Nico Huberf03ef4f2017-03-04 13:57:09 +010051 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
Nico Hubera43b1ee2017-07-09 15:40:25 +020060 void *const mapped = mmap(NULL, len, PROT_READ | PROT_WRITE,
61 MAP_ANONYMOUS | MAP_PRIVATE, -1, (off_t)0);
Nico Huberf03ef4f2017-03-04 13:57:09 +010062 if (mapped == MAP_FAILED)
63 return errno;
64
65 const int fd = open(path, O_RDONLY);
66 if (fd < 0)
67 goto _munmap;
68
69 xferred = 0;
70 do {
71 read_ret = read(fd, (uint8_t *)mapped + xferred, len - xferred);
72 if (read_ret > 0)
73 xferred += read_ret;
74 } while ((read_ret > 0 || (read_ret == -1 && errno == EINTR))
75 && xferred < len);
76 close(fd);
77
78 if (xferred < len)
79 goto _munmap;
80
81 if (mprotect(mapped, len, PROT_READ))
82 goto _munmap;
83
Nico Hubera43b1ee2017-07-09 15:40:25 +020084 *addr = (uint64_t)(uintptr_t)mapped;
Nico Huberf03ef4f2017-03-04 13:57:09 +010085 return 0;
86
87_munmap:
88 munmap(mapped, len);
89 return errno;
90}
91
Nico Hubera43b1ee2017-07-09 15:40:25 +020092int hw_file_map(uint64_t *const addr,
93 const char *const path,
Nico Huberf03ef4f2017-03-04 13:57:09 +010094 const uint32_t len,
95 const uint32_t mode,
96 const int copy)
97{
98 if (copy)
Nico Hubera43b1ee2017-07-09 15:40:25 +020099 return map_fill_from_file(addr, path, len, mode);
Nico Huberf03ef4f2017-03-04 13:57:09 +0100100 else
Nico Hubera43b1ee2017-07-09 15:40:25 +0200101 return map_file(addr, path, len, mode);
Nico Huberf03ef4f2017-03-04 13:57:09 +0100102}