1 /*
2 * The PCI Library -- Physical memory mapping for POSIX systems
3 *
4 * Copyright (c) 2023 Pali Rohár <[email protected]>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL v2+
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 /*
12 * Tell 32-bit platforms that we are interested in 64-bit variant of off_t type
13 * as 32-bit variant of off_t type is signed and so it cannot represent all
14 * possible 32-bit offsets. It is required because off_t type is used by mmap().
15 */
16 #define _FILE_OFFSET_BITS 64
17
18 #include "internal.h"
19 #include "physmem.h"
20
21 #include <limits.h>
22 #include <errno.h>
23 #include <sys/mman.h>
24 #include <sys/types.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27
28 #ifndef OFF_MAX
29 #define OFF_MAX ((((off_t)1 << (sizeof(off_t) * CHAR_BIT - 2)) - 1) * 2 + 1)
30 #endif
31
32 struct physmem {
33 int fd;
34 };
35
36 void
physmem_init_config(struct pci_access * a)37 physmem_init_config(struct pci_access *a)
38 {
39 pci_define_param(a, "devmem.path", PCI_PATH_DEVMEM_DEVICE, "Path to the /dev/mem device");
40 }
41
42 int
physmem_access(struct pci_access * a,int w)43 physmem_access(struct pci_access *a, int w)
44 {
45 const char *devmem = pci_get_param(a, "devmem.path");
46 a->debug("checking access permission of physical memory device %s for %s mode...", devmem, w ? "read/write" : "read-only");
47 return access(devmem, R_OK | (w ? W_OK : 0));
48 }
49
50 struct physmem *
physmem_open(struct pci_access * a,int w)51 physmem_open(struct pci_access *a, int w)
52 {
53 const char *devmem = pci_get_param(a, "devmem.path");
54 struct physmem *physmem = pci_malloc(a, sizeof(struct physmem));
55
56 a->debug("trying to open physical memory device %s in %s mode...", devmem, w ? "read/write" : "read-only");
57 physmem->fd = open(devmem, (w ? O_RDWR : O_RDONLY) | O_DSYNC); /* O_DSYNC bypass CPU cache for mmap() on Linux */
58 if (physmem->fd < 0)
59 {
60 pci_mfree(physmem);
61 return NULL;
62 }
63
64 return physmem;
65 }
66
67 void
physmem_close(struct physmem * physmem)68 physmem_close(struct physmem *physmem)
69 {
70 close(physmem->fd);
71 pci_mfree(physmem);
72 }
73
74 long
physmem_get_pagesize(struct physmem * physmem UNUSED)75 physmem_get_pagesize(struct physmem *physmem UNUSED)
76 {
77 return sysconf(_SC_PAGESIZE);
78 }
79
80 void *
physmem_map(struct physmem * physmem,u64 addr,size_t length,int w)81 physmem_map(struct physmem *physmem, u64 addr, size_t length, int w)
82 {
83 if (addr > OFF_MAX)
84 {
85 errno = EOVERFLOW;
86 return (void *)-1;
87 }
88 return mmap(NULL, length, PROT_READ | (w ? PROT_WRITE : 0), MAP_SHARED, physmem->fd, addr);
89 }
90
91 int
physmem_unmap(struct physmem * physmem UNUSED,void * ptr,size_t length)92 physmem_unmap(struct physmem *physmem UNUSED, void *ptr, size_t length)
93 {
94 return munmap(ptr, length);
95 }
96