]> mj.ucw.cz Git - pciutils.git/blob - lib/physmem-posix.c
libpci: ecam: Fix detect sequence when addresses are not specified
[pciutils.git] / lib / physmem-posix.c
1 /*
2  *      The PCI Library -- Physical memory mapping for POSIX systems
3  *
4  *      Copyright (c) 2023 Pali Rohár <pali@kernel.org>
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
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
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 *
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
68 physmem_close(struct physmem *physmem)
69 {
70   close(physmem->fd);
71   pci_mfree(physmem);
72 }
73
74 long
75 physmem_get_pagesize(struct physmem *physmem UNUSED)
76 {
77   return sysconf(_SC_PAGESIZE);
78 }
79
80 void *
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
92 physmem_unmap(struct physmem *physmem UNUSED, void *ptr, size_t length)
93 {
94   return munmap(ptr, length);
95 }