summaryrefslogtreecommitdiffstats
path: root/lib/physmem-posix.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 18:30:56 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 18:30:56 +0000
commitd3114e0edc60508fc1e44e6cd2733fb2a97cdaca (patch)
tree82d66db664dea6ee75010455b98b04f47fcc4a90 /lib/physmem-posix.c
parentInitial commit. (diff)
downloadpciutils-d3114e0edc60508fc1e44e6cd2733fb2a97cdaca.tar.xz
pciutils-d3114e0edc60508fc1e44e6cd2733fb2a97cdaca.zip
Adding upstream version 1:3.11.1.upstream/1%3.11.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'lib/physmem-posix.c')
-rw-r--r--lib/physmem-posix.c95
1 files changed, 95 insertions, 0 deletions
diff --git a/lib/physmem-posix.c b/lib/physmem-posix.c
new file mode 100644
index 0000000..7cd7e99
--- /dev/null
+++ b/lib/physmem-posix.c
@@ -0,0 +1,95 @@
+/*
+ * The PCI Library -- Physical memory mapping for POSIX systems
+ *
+ * Copyright (c) 2023 Pali Rohár <pali@kernel.org>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL v2+
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+/*
+ * Tell 32-bit platforms that we are interested in 64-bit variant of off_t type
+ * as 32-bit variant of off_t type is signed and so it cannot represent all
+ * possible 32-bit offsets. It is required because off_t type is used by mmap().
+ */
+#define _FILE_OFFSET_BITS 64
+
+#include "internal.h"
+#include "physmem.h"
+
+#include <limits.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#ifndef OFF_MAX
+#define OFF_MAX ((((off_t)1 << (sizeof(off_t) * CHAR_BIT - 2)) - 1) * 2 + 1)
+#endif
+
+struct physmem {
+ int fd;
+};
+
+void
+physmem_init_config(struct pci_access *a)
+{
+ pci_define_param(a, "devmem.path", PCI_PATH_DEVMEM_DEVICE, "Path to the /dev/mem device");
+}
+
+int
+physmem_access(struct pci_access *a, int w)
+{
+ const char *devmem = pci_get_param(a, "devmem.path");
+ a->debug("checking access permission of physical memory device %s for %s mode...", devmem, w ? "read/write" : "read-only");
+ return access(devmem, R_OK | (w ? W_OK : 0));
+}
+
+struct physmem *
+physmem_open(struct pci_access *a, int w)
+{
+ const char *devmem = pci_get_param(a, "devmem.path");
+ struct physmem *physmem = pci_malloc(a, sizeof(struct physmem));
+
+ a->debug("trying to open physical memory device %s in %s mode...", devmem, w ? "read/write" : "read-only");
+ physmem->fd = open(devmem, (w ? O_RDWR : O_RDONLY) | O_DSYNC); /* O_DSYNC bypass CPU cache for mmap() on Linux */
+ if (physmem->fd < 0)
+ {
+ pci_mfree(physmem);
+ return NULL;
+ }
+
+ return physmem;
+}
+
+void
+physmem_close(struct physmem *physmem)
+{
+ close(physmem->fd);
+ pci_mfree(physmem);
+}
+
+long
+physmem_get_pagesize(struct physmem *physmem UNUSED)
+{
+ return sysconf(_SC_PAGESIZE);
+}
+
+void *
+physmem_map(struct physmem *physmem, u64 addr, size_t length, int w)
+{
+ if (addr > OFF_MAX)
+ {
+ errno = EOVERFLOW;
+ return (void *)-1;
+ }
+ return mmap(NULL, length, PROT_READ | (w ? PROT_WRITE : 0), MAP_SHARED, physmem->fd, addr);
+}
+
+int
+physmem_unmap(struct physmem *physmem UNUSED, void *ptr, size_t length)
+{
+ return munmap(ptr, length);
+}