]> mj.ucw.cz Git - pciutils.git/commitdiff
libpci: Move physical memory mapping mmap() code from ecam/mmio-ports to physmem...
authorPali Rohár <pali@kernel.org>
Mon, 8 May 2023 19:15:07 +0000 (21:15 +0200)
committerMartin Mares <mj@ucw.cz>
Sun, 18 Feb 2024 15:18:43 +0000 (16:18 +0100)
This deduplicates physical memory mapping mmap() code found in ecam and
mmio-ports backends into common functions with new physmem API.

This new physmem API allows to implement also non-mmap() variants of
physical memory mapping.

lib/Makefile
lib/ecam.c
lib/mmio-ports.c
lib/physmem-access.h [new file with mode: 0644]
lib/physmem-posix.c [new file with mode: 0644]
lib/physmem.h [new file with mode: 0644]

index 4110ad3ff0ffeb3f8bc080c96cde17e3cf51768d..5c438eba6de22b1902d76d90e4b9a4b1bbbdd235 100644 (file)
@@ -79,6 +79,12 @@ ifdef PCI_OS_WINDOWS
 OBJS += win32-helpers
 endif
 
+ifndef PCI_OS_WINDOWS
+ifndef PCI_OS_DJGPP
+OBJS += physmem-posix
+endif
+endif
+
 all: $(PCILIB) $(PCILIBPC)
 
 ifeq ($(SHARED),no)
index c72eae60df3279371530c42adf6ae8f5235e0562..cb479c6b8fc833aa954287e0955b08fdcc7a0ac9 100644 (file)
@@ -8,14 +8,9 @@
  *     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 "physmem-access.h"
 
 #include <ctype.h>
 #include <errno.h>
@@ -24,9 +19,6 @@
 #include <string.h>
 #include <limits.h>
 
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <fcntl.h>
 #include <glob.h>
 #include <unistd.h>
 
 #include <kenv.h>
 #endif
 
-#ifndef OFF_MAX
-#define OFF_MAX (off_t)((1ULL << (sizeof(off_t) * CHAR_BIT - 1)) - 1)
-#endif
-
-static long pagesize;
-
 struct acpi_rsdp {
   char signature[8];
   u8 checksum;
@@ -92,6 +78,23 @@ struct acpi_mcfg {
   } allocations[0];
 } PCI_PACKED;
 
+struct mmap_cache {
+  void *map;
+  u64 addr;
+  u32 length;
+  int domain;
+  u8 bus;
+  int w;
+};
+
+// Back-end data linked to struct pci_access
+struct ecam_access {
+  struct acpi_mcfg *mcfg;
+  struct mmap_cache *cache;
+  struct physmem *physmem;
+  long pagesize;
+};
+
 static unsigned int
 get_rsdt_addresses_count(struct acpi_rsdt *rsdt)
 {
@@ -121,40 +124,40 @@ calculate_checksum(const u8 *bytes, int len)
 }
 
 static struct acpi_sdt *
-check_and_map_sdt(int fd, u64 addr, const char *signature, void **map_addr, u32 *map_length)
+check_and_map_sdt(struct physmem *physmem, long pagesize, u64 addr, const char *signature, void **map_addr, u32 *map_length)
 {
   struct acpi_sdt *sdt;
   char sdt_signature[sizeof(sdt->signature)];
   u32 length;
   void *map;
 
-  if (addr > OFF_MAX - sizeof(*sdt))
+  if (addr + sizeof(*sdt) < addr)
     return NULL;
 
-  map = mmap(NULL, sizeof(*sdt) + (addr & (pagesize-1)), PROT_READ, MAP_SHARED, fd, addr & ~(pagesize-1));
-  if (map == MAP_FAILED)
+  map = physmem_map(physmem, addr & ~(pagesize-1), sizeof(*sdt) + (addr & (pagesize-1)), 0);
+  if (map == (void *)-1)
     return NULL;
 
   sdt = (struct acpi_sdt *)((unsigned char *)map + (addr & (pagesize-1)));
   length = sdt->length;
   memcpy(sdt_signature, sdt->signature, sizeof(sdt->signature));
 
-  munmap(map, sizeof(*sdt) + (addr & (pagesize-1)));
+  physmem_unmap(physmem, map, sizeof(*sdt) + (addr & (pagesize-1)));
 
   if (memcmp(sdt_signature, signature, sizeof(sdt_signature)) != 0)
     return NULL;
   if (length < sizeof(*sdt))
     return NULL;
 
-  map = mmap(NULL, length + (addr & (pagesize-1)), PROT_READ, MAP_SHARED, fd, addr & ~(pagesize-1));
-  if (map == MAP_FAILED)
+  map = physmem_map(physmem, addr & ~(pagesize-1), length + (addr & (pagesize-1)), 0);
+  if (map == (void *)-1)
     return NULL;
 
   sdt = (struct acpi_sdt *)((unsigned char *)map + (addr & (pagesize-1)));
 
   if (calculate_checksum((u8 *)sdt, sdt->length) != 0)
     {
-      munmap(map, length + (addr & (pagesize-1)));
+      physmem_unmap(physmem, map, length + (addr & (pagesize-1)));
       return NULL;
     }
 
@@ -174,20 +177,20 @@ check_rsdp(struct acpi_rsdp *rsdp)
 }
 
 static int
-check_and_parse_rsdp(int fd, off_t addr, u32 *rsdt_address, u64 *xsdt_address)
+check_and_parse_rsdp(struct physmem *physmem, long pagesize, u64 addr, u32 *rsdt_address, u64 *xsdt_address)
 {
   struct acpi_rsdp *rsdp;
   unsigned char buf[sizeof(*rsdp) + sizeof(*rsdp->rsdp20)];
   void *map;
 
-  map = mmap(NULL, sizeof(buf) + (addr & (pagesize-1)), PROT_READ, MAP_SHARED, fd, addr & ~(pagesize-1));
-  if (map == MAP_FAILED)
+  map = physmem_map(physmem, addr & ~(pagesize-1), sizeof(buf) + (addr & (pagesize-1)), 0);
+  if (map == (void *)-1)
     return 0;
 
   rsdp = (struct acpi_rsdp *)buf;
   memcpy(rsdp, (unsigned char *)map + (addr & (pagesize-1)), sizeof(buf));
 
-  munmap(map, sizeof(buf));
+  physmem_unmap(physmem, map, sizeof(buf));
 
   if (!check_rsdp(rsdp))
     return 0;
@@ -204,20 +207,22 @@ check_and_parse_rsdp(int fd, off_t addr, u32 *rsdt_address, u64 *xsdt_address)
   return 1;
 }
 
-static off_t
+static u64
 find_rsdp_address(struct pci_access *a, const char *efisystab, int use_bsd UNUSED, int use_x86bios UNUSED)
 {
-  unsigned long long ullnum;
+  u64 ullnum;
 #if defined (__FreeBSD__) || defined (__DragonFly__) || defined(__NetBSD__)
   unsigned long ulnum;
 #endif
   char buf[1024];
   char *endptr;
-  off_t acpi20;
-  off_t acpi;
+  u64 acpi20;
+  u64 acpi;
 #if defined(__amd64__) || defined(__i386__)
-  off_t rsdp_addr;
-  off_t addr;
+  struct ecam_access *eacc = a->backend_data;
+  struct physmem *physmem = eacc->physmem;
+  u64 rsdp_addr;
+  u64 addr;
   void *map;
 #endif
   size_t len;
@@ -240,19 +245,21 @@ find_rsdp_address(struct pci_access *a, const char *efisystab, int use_bsd UNUSE
                 {
                   errno = 0;
                   ullnum = strtoull(buf+7, &endptr, 16);
-                  if (!errno && !*endptr && ullnum <= OFF_MAX)
+                  if (!errno && !*endptr)
                     acpi20 = ullnum;
                 }
               else if (strncmp(buf, "ACPI=", 5) == 0 && isxdigit(buf[5]))
                 {
                   errno = 0;
                   ullnum = strtoull(buf+5, &endptr, 16);
-                  if (!errno && !*endptr && ullnum <= OFF_MAX)
+                  if (!errno && !*endptr)
                     acpi = ullnum;
                 }
             }
           fclose(f);
         }
+      else
+        a->debug("opening failed: %s...", strerror(errno));
 
       if (acpi20)
         return acpi20;
@@ -269,14 +276,14 @@ find_rsdp_address(struct pci_access *a, const char *efisystab, int use_bsd UNUSE
         {
           errno = 0;
           ullnum = strtoull(buf, &endptr, 16);
-          if (!errno && !*endptr && ullnum <= OFF_MAX)
+          if (!errno && !*endptr)
             return ullnum;
         }
 
       /* Then try FreeBSD sysctl machdep.acpi_root */
       a->debug("calling sysctl machdep.acpi_root...");
       len = sizeof(ulnum);
-      if (sysctlbyname("machdep.acpi_root", &ulnum, &len, NULL, 0) == 0 && ulnum <= OFF_MAX)
+      if (sysctlbyname("machdep.acpi_root", &ulnum, &len, NULL, 0) == 0)
         return ulnum;
     }
 #endif
@@ -287,7 +294,7 @@ find_rsdp_address(struct pci_access *a, const char *efisystab, int use_bsd UNUSE
       /* Try NetBSD sysctl hw.acpi.root */
       a->debug("calling sysctl hw.acpi.root...");
       len = sizeof(ulnum);
-      if (sysctlbyname("hw.acpi.root", &ulnum, &len, NULL, 0) == 0 && ulnum <= OFF_MAX)
+      if (sysctlbyname("hw.acpi.root", &ulnum, &len, NULL, 0) == 0)
         return ulnum;
     }
 #endif
@@ -299,8 +306,8 @@ find_rsdp_address(struct pci_access *a, const char *efisystab, int use_bsd UNUSE
 
       /* Scan first kB of Extended BIOS Data Area */
       a->debug("scanning first kB of EBDA...");
-      map = mmap(NULL, 0x40E + 1024, PROT_READ, MAP_SHARED, a->fd, 0);
-      if (map != MAP_FAILED)
+      map = physmem_map(physmem, 0, 0x40E + 1024, 0);
+      if (map != (void *)-1)
         {
           for (addr = 0x40E; addr < 0x40E + 1024; addr += 16)
             {
@@ -310,16 +317,19 @@ find_rsdp_address(struct pci_access *a, const char *efisystab, int use_bsd UNUSE
                   break;
                 }
             }
-          munmap(map, 0x40E + 1024);
+          if (physmem_unmap(physmem, map, 0x40E + 1024) != 0)
+            a->debug("unmapping of EBDA failed: %s...", strerror(errno));
         }
+      else
+        a->debug("mapping of EBDA failed: %s...", strerror(errno));
 
       if (rsdp_addr)
         return rsdp_addr;
 
       /* Scan the main BIOS area below 1 MB */
       a->debug("scanning BIOS below 1 MB...");
-      map = mmap(NULL, 0x20000, PROT_READ, MAP_SHARED, a->fd, 0xE0000);
-      if (map != MAP_FAILED)
+      map = physmem_map(physmem, 0xE0000, 0x20000, 0);
+      if (map != (void *)-1)
         {
           for (addr = 0x0; addr < 0x20000; addr += 16)
             {
@@ -329,8 +339,11 @@ find_rsdp_address(struct pci_access *a, const char *efisystab, int use_bsd UNUSE
                   break;
                 }
             }
-          munmap(map, 0x20000);
+          if (physmem_unmap(physmem, map, 0x20000) != 0)
+            a->debug("unmapping of BIOS failed: %s...", strerror(errno));
         }
+      else
+        a->debug("mapping of BIOS failed: %s...", strerror(errno));
 
       if (rsdp_addr)
         return rsdp_addr;
@@ -343,20 +356,24 @@ find_rsdp_address(struct pci_access *a, const char *efisystab, int use_bsd UNUSE
 static struct acpi_mcfg *
 find_mcfg(struct pci_access *a, const char *acpimcfg, const char *efisystab, int use_bsd, int use_x86bios)
 {
+  struct ecam_access *eacc = a->backend_data;
+  struct physmem *physmem = eacc->physmem;
+  long pagesize = eacc->pagesize;
   struct acpi_xsdt *xsdt;
   struct acpi_rsdt *rsdt;
   struct acpi_mcfg *mcfg;
   struct acpi_sdt *sdt;
   unsigned int i, count;
-  off_t rsdp_address;
+  u64 rsdp_address;
   u64 xsdt_address;
   u32 rsdt_address;
   void *map_addr;
   u32 map_length;
   void *map2_addr;
   u32 map2_length;
-  off_t length;
-  int mcfg_fd;
+  long length;
+  FILE *mcfg_file;
+  const char *path;
   glob_t mcfg_glob;
   int ret;
 
@@ -365,26 +382,30 @@ find_mcfg(struct pci_access *a, const char *acpimcfg, const char *efisystab, int
       ret = glob(acpimcfg, GLOB_NOCHECK, NULL, &mcfg_glob);
       if (ret == 0)
         {
-          a->debug("reading acpi mcfg file: %s...", mcfg_glob.gl_pathv[0]);
-          mcfg_fd = open(mcfg_glob.gl_pathv[0], O_RDONLY);
+          path = mcfg_glob.gl_pathv[0];
+          a->debug("reading acpi mcfg file: %s...", path);
+          mcfg_file = fopen(path, "rb");
           globfree(&mcfg_glob);
-          if (mcfg_fd >= 0)
+          if (mcfg_file)
             {
-              length = lseek(mcfg_fd, 0, SEEK_END);
-              if (length != (off_t)-1 && length > (off_t)sizeof(*mcfg))
+              if (fseek(mcfg_file, 0, SEEK_END) == 0)
+                length = ftell(mcfg_file);
+              else
+                length = -1;
+              if (length > 0 && (size_t)length > sizeof(*mcfg))
                 {
-                  lseek(mcfg_fd, 0, SEEK_SET);
+                  rewind(mcfg_file);
                   mcfg = pci_malloc(a, length);
-                  if (read(mcfg_fd, mcfg, length) == length &&
+                  if (fread(mcfg, 1, length, mcfg_file) == (size_t)length &&
                       memcmp(mcfg->sdt.signature, "MCFG", 4) == 0 &&
-                      mcfg->sdt.length <= length &&
+                      mcfg->sdt.length <= (size_t)length &&
                       calculate_checksum((u8 *)mcfg, mcfg->sdt.length) == 0)
                     {
-                      close(mcfg_fd);
+                      fclose(mcfg_file);
                       return mcfg;
                     }
                 }
-              close(mcfg_fd);
+              fclose(mcfg_file);
             }
           a->debug("failed...");
         }
@@ -399,34 +420,34 @@ find_mcfg(struct pci_access *a, const char *acpimcfg, const char *efisystab, int
       a->debug("not found...");
       return NULL;
     }
-  a->debug("found at 0x%llx...", (unsigned long long)rsdp_address);
+  a->debug("found at 0x%" PCI_U64_FMT_X "...", rsdp_address);
 
-  if (!check_and_parse_rsdp(a->fd, rsdp_address, &rsdt_address, &xsdt_address))
+  if (!check_and_parse_rsdp(physmem, pagesize, rsdp_address, &rsdt_address, &xsdt_address))
     {
       a->debug("invalid...");
       return NULL;
     }
 
   mcfg = NULL;
-  a->debug("searching for ACPI MCFG (XSDT=0x%llx, RSDT=0x%x)...", (unsigned long long)xsdt_address, rsdt_address);
+  a->debug("searching for ACPI MCFG (XSDT=0x%" PCI_U64_FMT_X ", RSDT=0x%lx)...", xsdt_address, (unsigned long)rsdt_address);
 
-  xsdt = xsdt_address ? (struct acpi_xsdt *)check_and_map_sdt(a->fd, xsdt_address, "XSDT", &map_addr, &map_length) : NULL;
+  xsdt = xsdt_address ? (struct acpi_xsdt *)check_and_map_sdt(physmem, pagesize, xsdt_address, "XSDT", &map_addr, &map_length) : NULL;
   if (xsdt)
     {
       a->debug("via XSDT...");
       count = get_xsdt_addresses_count(xsdt);
       for (i = 0; i < count; i++)
         {
-          sdt = check_and_map_sdt(a->fd, xsdt->sdt_addresses[i], "MCFG", &map2_addr, &map2_length);
+          sdt = check_and_map_sdt(physmem, pagesize, xsdt->sdt_addresses[i], "MCFG", &map2_addr, &map2_length);
           if (sdt)
             {
               mcfg = pci_malloc(a, sdt->length);
               memcpy(mcfg, sdt, sdt->length);
-              munmap(map2_addr, map2_length);
+              physmem_unmap(physmem, map2_addr, map2_length);
               break;
             }
         }
-      munmap(map_addr, map_length);
+      physmem_unmap(physmem, map_addr, map_length);
       if (mcfg)
         {
           a->debug("found...");
@@ -434,23 +455,23 @@ find_mcfg(struct pci_access *a, const char *acpimcfg, const char *efisystab, int
         }
     }
 
-  rsdt = (struct acpi_rsdt *)check_and_map_sdt(a->fd, rsdt_address, "RSDT", &map_addr, &map_length);
+  rsdt = (struct acpi_rsdt *)check_and_map_sdt(physmem, pagesize, rsdt_address, "RSDT", &map_addr, &map_length);
   if (rsdt)
     {
       a->debug("via RSDT...");
       count = get_rsdt_addresses_count(rsdt);
       for (i = 0; i < count; i++)
         {
-          sdt = check_and_map_sdt(a->fd, rsdt->sdt_addresses[i], "MCFG", &map2_addr, &map2_length);
+          sdt = check_and_map_sdt(physmem, pagesize, rsdt->sdt_addresses[i], "MCFG", &map2_addr, &map2_length);
           if (sdt)
             {
               mcfg = pci_malloc(a, sdt->length);
               memcpy(mcfg, sdt, sdt->length);
-              munmap(map2_addr, map2_length);
+              physmem_unmap(physmem, map2_addr, map2_length);
               break;
             }
         }
-      munmap(map_addr, map_length);
+      physmem_unmap(physmem, map_addr, map_length);
       if (mcfg)
         {
           a->debug("found...");
@@ -463,7 +484,7 @@ find_mcfg(struct pci_access *a, const char *acpimcfg, const char *efisystab, int
 }
 
 static void
-get_mcfg_allocation(struct acpi_mcfg *mcfg, unsigned int i, int *domain, u8 *start_bus, u8 *end_bus, off_t *addr, u32 *length)
+get_mcfg_allocation(struct acpi_mcfg *mcfg, unsigned int i, int *domain, u8 *start_bus, u8 *end_bus, u64 *addr, u32 *length)
 {
   int buses = (int)mcfg->allocations[i].end_bus_number - (int)mcfg->allocations[i].start_bus_number + 1;
 
@@ -480,15 +501,15 @@ get_mcfg_allocation(struct acpi_mcfg *mcfg, unsigned int i, int *domain, u8 *sta
 }
 
 static int
-parse_next_addrs(const char *addrs, const char **next, int *domain, u8 *start_bus, u8 *end_bus, off_t *addr, u32 *length)
+parse_next_addrs(const char *addrs, const char **next, int *domain, u8 *start_bus, u8 *end_bus, u64 *addr, u32 *length)
 {
-  unsigned long long ullnum;
+  u64 ullnum;
   const char *sep1, *sep2;
   int addr_len;
   char *endptr;
   long num;
   int buses;
-  unsigned long long start_addr;
+  u64 start_addr;
 
   if (!*addrs)
     {
@@ -563,7 +584,7 @@ parse_next_addrs(const char *addrs, const char **next, int *domain, u8 *start_bu
 
   errno = 0;
   ullnum = strtoull(sep2+1, &endptr, 16);
-  if (errno || (ullnum & 3) || ullnum > OFF_MAX)
+  if (errno || (ullnum & 3))
     return 0;
   if (addr)
     *addr = ullnum;
@@ -577,7 +598,7 @@ parse_next_addrs(const char *addrs, const char **next, int *domain, u8 *start_bu
           if (end_bus)
             *end_bus = 0xff;
         }
-      if ((unsigned)buses * 32 * 8 * 4096 > OFF_MAX - start_addr)
+      if (start_addr + (unsigned)buses * 32 * 8 * 4096 < start_addr)
         return 0;
       if (length)
         *length = buses * 32 * 8 * 4096;
@@ -588,9 +609,9 @@ parse_next_addrs(const char *addrs, const char **next, int *domain, u8 *start_bu
         return 0;
       errno = 0;
       ullnum = strtoull(endptr+1, &endptr, 16);
-      if (errno || endptr != addrs + addr_len || (ullnum & 3) || ullnum > OFF_MAX || ullnum > 256 * 32 * 8 * 4096)
+      if (errno || endptr != addrs + addr_len || (ullnum & 3) || ullnum > 256 * 32 * 8 * 4096)
         return 0;
-      if (ullnum > OFF_MAX - start_addr)
+      if (start_addr + ullnum < start_addr)
         return 0;
       if (buses > 0 && ullnum > (unsigned)buses * 32 * 8 * 4096)
         return 0;
@@ -619,7 +640,7 @@ validate_addrs(const char *addrs)
 }
 
 static int
-calculate_bus_addr(u8 start_bus, off_t start_addr, u32 total_length, u8 bus, off_t *addr, u32 *length)
+calculate_bus_addr(u8 start_bus, u64 start_addr, u32 total_length, u8 bus, u64 *addr, u32 *length)
 {
   u32 offset;
 
@@ -637,12 +658,12 @@ calculate_bus_addr(u8 start_bus, off_t start_addr, u32 total_length, u8 bus, off
 }
 
 static int
-get_bus_addr(struct acpi_mcfg *mcfg, const char *addrs, int domain, u8 bus, off_t *addr, u32 *length)
+get_bus_addr(struct acpi_mcfg *mcfg, const char *addrs, int domain, u8 bus, u64 *addr, u32 *length)
 {
   int cur_domain;
   u8 start_bus;
   u8 end_bus;
-  off_t start_addr;
+  u64 start_addr;
   u32 total_length;
   int i, count;
 
@@ -670,33 +691,18 @@ get_bus_addr(struct acpi_mcfg *mcfg, const char *addrs, int domain, u8 bus, off_
     }
 }
 
-struct mmap_cache
-{
-  void *map;
-  off_t addr;
-  u32 length;
-  int domain;
-  u8 bus;
-  int w;
-};
-
-// Back-end data linked to struct pci_access
-struct ecam_access
-{
-  struct acpi_mcfg *mcfg;
-  struct mmap_cache *cache;
-};
-
 static void
 munmap_reg(struct pci_access *a)
 {
   struct ecam_access *eacc = a->backend_data;
   struct mmap_cache *cache = eacc->cache;
+  struct physmem *physmem = eacc->physmem;
+  long pagesize = eacc->pagesize;
 
   if (!cache)
     return;
 
-  munmap(cache->map, cache->length + (cache->addr & (pagesize-1)));
+  physmem_unmap(physmem, cache->map, cache->length + (cache->addr & (pagesize-1)));
   pci_mfree(cache);
   eacc->cache = NULL;
 }
@@ -706,9 +712,11 @@ mmap_reg(struct pci_access *a, int w, int domain, u8 bus, u8 dev, u8 func, int p
 {
   struct ecam_access *eacc = a->backend_data;
   struct mmap_cache *cache = eacc->cache;
+  struct physmem *physmem = eacc->physmem;
+  long pagesize = eacc->pagesize;
   const char *addrs;
   void *map;
-  off_t addr;
+  u64 addr;
   u32 length;
   u32 offset;
 
@@ -724,12 +732,12 @@ mmap_reg(struct pci_access *a, int w, int domain, u8 bus, u8 dev, u8 func, int p
       if (!get_bus_addr(eacc->mcfg, addrs, domain, bus, &addr, &length))
         return 0;
 
-      map = mmap(NULL, length + (addr & (pagesize-1)), w ? PROT_WRITE : PROT_READ, MAP_SHARED, a->fd, addr & ~(pagesize-1));
-      if (map == MAP_FAILED)
+      map = physmem_map(physmem, addr & ~(pagesize-1), length + (addr & (pagesize-1)), w);
+      if (map == (void *)-1)
         return 0;
 
       if (cache)
-        munmap(cache->map, cache->length + (cache->addr & (pagesize-1)));
+        physmem_unmap(physmem, cache->map, cache->length + (cache->addr & (pagesize-1)));
       else
         cache = eacc->cache = pci_malloc(a, sizeof(*cache));
 
@@ -754,46 +762,10 @@ mmap_reg(struct pci_access *a, int w, int domain, u8 bus, u8 dev, u8 func, int p
   return 1;
 }
 
-static void
-writeb(unsigned char value, volatile void *addr)
-{
-  *(volatile unsigned char *)addr = value;
-}
-
-static void
-writew(unsigned short value, volatile void *addr)
-{
-  *(volatile unsigned short *)addr = value;
-}
-
-static void
-writel(unsigned int value, volatile void *addr)
-{
-  *(volatile unsigned int *)addr = value;
-}
-
-static unsigned char
-readb(volatile void *addr)
-{
-  return *(volatile unsigned char *)addr;
-}
-
-static unsigned short
-readw(volatile void *addr)
-{
-  return *(volatile unsigned short *)addr;
-}
-
-static unsigned int
-readl(volatile void *addr)
-{
-  return *(volatile unsigned int *)addr;
-}
-
 static void
 ecam_config(struct pci_access *a)
 {
-  pci_define_param(a, "devmem.path", PCI_PATH_DEVMEM_DEVICE, "Path to the /dev/mem device");
+  physmem_init_config(a);
   pci_define_param(a, "ecam.acpimcfg", PCI_PATH_ACPI_MCFG, "Path to the ACPI MCFG table");
   pci_define_param(a, "ecam.efisystab", PCI_PATH_EFI_SYSTAB, "Path to the EFI system table");
 #if defined (__FreeBSD__) || defined (__DragonFly__) || defined(__NetBSD__)
@@ -809,7 +781,6 @@ static int
 ecam_detect(struct pci_access *a)
 {
   int use_addrs = 1, use_acpimcfg = 1, use_efisystab = 1, use_bsd = 1, use_x86bios = 1;
-  const char *devmem = pci_get_param(a, "devmem.path");
   const char *acpimcfg = pci_get_param(a, "ecam.acpimcfg");
   const char *efisystab = pci_get_param(a, "ecam.efisystab");
 #if defined (__FreeBSD__) || defined (__DragonFly__) || defined(__NetBSD__)
@@ -849,7 +820,7 @@ ecam_detect(struct pci_access *a)
   else
     use_acpimcfg = 0;
 
-  if (access(efisystab, R_OK))
+  if (!efisystab[0] || access(efisystab, R_OK))
     {
       if (efisystab[0])
         a->debug("cannot access efisystab: %s: %s...", efisystab, strerror(errno));
@@ -888,16 +859,16 @@ ecam_detect(struct pci_access *a)
       return 0;
     }
 
-  if (access(devmem, R_OK))
+  if (physmem_access(a, 0))
     {
-      a->debug("cannot access physical memory via %s: %s", devmem, strerror(errno));
+      a->debug("cannot access physical memory: %s", strerror(errno));
       return 0;
     }
 
   if (use_addrs)
-    a->debug("using %s with ecam addresses %s", devmem, addrs);
+    a->debug("using with ecam addresses %s", addrs);
   else
-    a->debug("using %s with%s%s%s%s%s%s", devmem, use_acpimcfg ? " acpimcfg=" : "", use_acpimcfg ? acpimcfg : "", use_efisystab ? " efisystab=" : "", use_efisystab ? efisystab : "", use_bsd ? " bsd" : "", use_x86bios ? " x86bios" : "");
+    a->debug("using with%s%s%s%s%s%s", use_acpimcfg ? " acpimcfg=" : "", use_acpimcfg ? acpimcfg : "", use_efisystab ? " efisystab=" : "", use_efisystab ? efisystab : "", use_bsd ? " bsd" : "", use_x86bios ? " x86bios" : "");
 
   return 1;
 }
@@ -905,7 +876,6 @@ ecam_detect(struct pci_access *a)
 static void
 ecam_init(struct pci_access *a)
 {
-  const char *devmem = pci_get_param(a, "devmem.path");
   const char *acpimcfg = pci_get_param(a, "ecam.acpimcfg");
   const char *efisystab = pci_get_param(a, "ecam.efisystab");
 #if defined (__FreeBSD__) || defined (__DragonFly__) || defined(__NetBSD__)
@@ -915,24 +885,32 @@ ecam_init(struct pci_access *a)
   const char *x86bios = pci_get_param(a, "ecam.x86bios");
 #endif
   const char *addrs = pci_get_param(a, "ecam.addrs");
-  struct acpi_mcfg *mcfg = NULL;
+  struct physmem *physmem = NULL;
   struct ecam_access *eacc = NULL;
+  long pagesize = 0;
   int use_bsd = 0;
   int use_x86bios = 0;
   int test_domain = 0;
   u8 test_bus = 0;
   volatile void *test_reg;
 
-  pagesize = sysconf(_SC_PAGESIZE);
-  if (pagesize < 0)
-    a->error("Cannot get page size: %s.", strerror(errno));
-
   if (!validate_addrs(addrs))
     a->error("Option ecam.addrs has invalid address format \"%s\".", addrs);
 
-  a->fd = open(devmem, (a->writeable ? O_RDWR : O_RDONLY) | O_DSYNC);
-  if (a->fd < 0)
-    a->error("Cannot open %s: %s.", devmem, strerror(errno));
+  physmem = physmem_open(a, a->writeable);
+  if (!physmem)
+    a->error("Cannot open physcal memory: %s.", strerror(errno));
+
+  pagesize = physmem_get_pagesize(physmem);
+  if (pagesize <= 0)
+    a->error("Cannot get page size: %s.", strerror(errno));
+
+  eacc = pci_malloc(a, sizeof(*eacc));
+  eacc->mcfg = NULL;
+  eacc->cache = NULL;
+  eacc->physmem = physmem;
+  eacc->pagesize = pagesize;
+  a->backend_data = eacc;
 
   if (!*addrs)
     {
@@ -944,18 +922,13 @@ ecam_init(struct pci_access *a)
       if (strcmp(x86bios, "0") != 0)
         use_x86bios = 1;
 #endif
-      mcfg = find_mcfg(a, acpimcfg, efisystab, use_bsd, use_x86bios);
-      if (!mcfg)
+      eacc->mcfg = find_mcfg(a, acpimcfg, efisystab, use_bsd, use_x86bios);
+      if (!eacc->mcfg)
         a->error("Option ecam.addrs was not specified and ACPI MCFG table cannot be found.");
     }
 
-  eacc = pci_malloc(a, sizeof(*eacc));
-  eacc->mcfg = mcfg;
-  eacc->cache = NULL;
-  a->backend_data = eacc;
-
-  if (mcfg)
-    get_mcfg_allocation(mcfg, 0, &test_domain, &test_bus, NULL, NULL, NULL);
+  if (eacc->mcfg)
+    get_mcfg_allocation(eacc->mcfg, 0, &test_domain, &test_bus, NULL, NULL, NULL);
   else
     parse_next_addrs(addrs, NULL, &test_domain, &test_bus, NULL, NULL, NULL);
 
@@ -969,16 +942,11 @@ ecam_cleanup(struct pci_access *a)
 {
   struct ecam_access *eacc = a->backend_data;
 
-  if (a->fd < 0)
-    return;
-
   munmap_reg(a);
+  physmem_close(eacc->physmem);
   pci_mfree(eacc->mcfg);
   pci_mfree(eacc);
   a->backend_data = NULL;
-
-  close(a->fd);
-  a->fd = -1;
 }
 
 static void
@@ -1037,13 +1005,13 @@ ecam_read(struct pci_dev *d, int pos, byte *buf, int len)
   switch (len)
     {
     case 1:
-      buf[0] = readb(reg);
+      buf[0] = physmem_readb(reg);
       break;
     case 2:
-      ((u16 *) buf)[0] = readw(reg);
+      ((u16 *) buf)[0] = physmem_readw(reg);
       break;
     case 4:
-      ((u32 *) buf)[0] = readl(reg);
+      ((u32 *) buf)[0] = physmem_readl(reg);
       break;
     }
 
@@ -1067,13 +1035,13 @@ ecam_write(struct pci_dev *d, int pos, byte *buf, int len)
   switch (len)
     {
     case 1:
-      writeb(buf[0], reg);
+      physmem_writeb(buf[0], reg);
       break;
     case 2:
-      writew(((u16 *) buf)[0], reg);
+      physmem_writew(((u16 *) buf)[0], reg);
       break;
     case 4:
-      writel(((u32 *) buf)[0], reg);
+      physmem_writel(((u32 *) buf)[0], reg);
       break;
     }
 
index 9a9b48dd10d65bbf1f21730447aa40dea21fefb7..cac8a7e35ad138269d11d3e7db1d74db6959b25d 100644 (file)
@@ -8,64 +8,58 @@
  *     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 "physmem-access.h"
 
 #include <ctype.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
-#include <limits.h>
-
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <unistd.h>
 
-#ifndef OFF_MAX
-#define OFF_MAX (off_t)((1ULL << (sizeof(off_t) * CHAR_BIT - 1)) - 1)
-#endif
-
-struct mmio_cache
-{
-  off_t addr_page;
-  off_t data_page;
+struct mmio_cache {
+  u64 addr_page;
+  u64 data_page;
   void *addr_map;
   void *data_map;
 };
 
-static long pagesize;
+struct mmio_access {
+  struct mmio_cache *cache;
+  struct physmem *physmem;
+  long pagesize;
+};
 
 static void
 munmap_regs(struct pci_access *a)
 {
-  struct mmio_cache *cache = a->backend_data;
+  struct mmio_access *macc = a->backend_data;
+  struct mmio_cache *cache = macc->cache;
+  struct physmem *physmem = macc->physmem;
+  long pagesize = macc->pagesize;
 
   if (!cache)
     return;
 
-  munmap(cache->addr_map, pagesize);
+  physmem_unmap(physmem, cache->addr_map, pagesize);
   if (cache->addr_page != cache->data_page)
-    munmap(cache->data_map, pagesize);
+    physmem_unmap(physmem, cache->data_map, pagesize);
 
-  pci_mfree(a->backend_data);
-  a->backend_data = NULL;
+  pci_mfree(macc->cache);
+  macc->cache = NULL;
 }
 
 static int
-mmap_regs(struct pci_access *a, off_t addr_reg, off_t data_reg, int data_off, volatile void **addr, volatile void **data)
+mmap_regs(struct pci_access *a, u64 addr_reg, u64 data_reg, int data_off, volatile void **addr, volatile void **data)
 {
-  struct mmio_cache *cache = a->backend_data;
-  off_t addr_page = addr_reg & ~(pagesize-1);
-  off_t data_page = data_reg & ~(pagesize-1);
-  void *addr_map = MAP_FAILED;
-  void *data_map = MAP_FAILED;
+  struct mmio_access *macc = a->backend_data;
+  struct mmio_cache *cache = macc->cache;
+  struct physmem *physmem = macc->physmem;
+  long pagesize = macc->pagesize;
+  u64 addr_page = addr_reg & ~(pagesize-1);
+  u64 data_page = data_reg & ~(pagesize-1);
+  void *addr_map = (void *)-1;
+  void *data_map = (void *)-1;
 
   if (cache && cache->addr_page == addr_page)
     addr_map = cache->addr_map;
@@ -73,35 +67,35 @@ mmap_regs(struct pci_access *a, off_t addr_reg, off_t data_reg, int data_off, vo
   if (cache && cache->data_page == data_page)
     data_map = cache->data_map;
 
-  if (addr_map == MAP_FAILED)
-    addr_map = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, a->fd, addr_page);
+  if (addr_map == (void *)-1)
+    addr_map = physmem_map(physmem, addr_page, pagesize, 1);
 
-  if (addr_map == MAP_FAILED)
+  if (addr_map == (void *)-1)
     return 0;
 
-  if (data_map == MAP_FAILED)
+  if (data_map == (void *)-1)
     {
       if (data_page == addr_page)
         data_map = addr_map;
       else
-        data_map = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, a->fd, data_page);
+        data_map = physmem_map(physmem, data_page, pagesize, 1);
     }
 
-  if (data_map == MAP_FAILED)
+  if (data_map == (void *)-1)
     {
       if (!cache || cache->addr_map != addr_map)
-        munmap(addr_map, pagesize);
+        physmem_unmap(physmem, addr_map, pagesize);
       return 0;
     }
 
   if (cache && cache->addr_page != addr_page)
-    munmap(cache->addr_map, pagesize);
+    physmem_unmap(physmem, cache->addr_map, pagesize);
 
   if (cache && cache->data_page != data_page && cache->data_page != cache->addr_page)
-    munmap(cache->data_map, pagesize);
+    physmem_unmap(physmem, cache->data_map, pagesize);
 
   if (!cache)
-    cache = a->backend_data = pci_malloc(a, sizeof(*cache));
+    cache = macc->cache = pci_malloc(a, sizeof(*cache));
 
   cache->addr_page = addr_page;
   cache->data_page = data_page;
@@ -113,47 +107,11 @@ mmap_regs(struct pci_access *a, off_t addr_reg, off_t data_reg, int data_off, vo
   return 1;
 }
 
-static void
-writeb(unsigned char value, volatile void *addr)
-{
-  *(volatile unsigned char *)addr = value;
-}
-
-static void
-writew(unsigned short value, volatile void *addr)
-{
-  *(volatile unsigned short *)addr = value;
-}
-
-static void
-writel(u32 value, volatile void *addr)
-{
-  *(volatile u32 *)addr = value;
-}
-
-static unsigned char
-readb(volatile void *addr)
-{
-  return *(volatile unsigned char *)addr;
-}
-
-static unsigned short
-readw(volatile void *addr)
-{
-  return *(volatile unsigned short *)addr;
-}
-
-static u32
-readl(volatile void *addr)
-{
-  return *(volatile u32 *)addr;
-}
-
 static int
 validate_addrs(const char *addrs)
 {
   const char *sep, *next;
-  unsigned long long num;
+  u64 num;
   char *endptr;
 
   if (!*addrs)
@@ -174,12 +132,12 @@ validate_addrs(const char *addrs)
 
       errno = 0;
       num = strtoull(addrs, &endptr, 16);
-      if (errno || endptr != sep || (num & 3) || num > OFF_MAX)
+      if (errno || endptr != sep || (num & 3))
         return 0;
 
       errno = 0;
       num = strtoull(sep+1, &endptr, 16);
-      if (errno || endptr != next || (num & 3) || num > OFF_MAX)
+      if (errno || endptr != next || (num & 3))
         return 0;
 
       if (!*next)
@@ -202,7 +160,7 @@ get_domain_count(const char *addrs)
 }
 
 static int
-get_domain_addr(const char *addrs, int domain, off_t *addr_reg, off_t *data_reg)
+get_domain_addr(const char *addrs, int domain, u64 *addr_reg, u64 *data_reg)
 {
   char *endptr;
 
@@ -223,14 +181,14 @@ get_domain_addr(const char *addrs, int domain, off_t *addr_reg, off_t *data_reg)
 static void
 conf1_config(struct pci_access *a)
 {
-  pci_define_param(a, "devmem.path", PCI_PATH_DEVMEM_DEVICE, "Path to the /dev/mem device");
+  physmem_init_config(a);
   pci_define_param(a, "mmio-conf1.addrs", "", "Physical addresses of memory mapped Intel conf1 interface"); /* format: 0xaddr1/0xdata1,0xaddr2/0xdata2,... */
 }
 
 static void
 conf1_ext_config(struct pci_access *a)
 {
-  pci_define_param(a, "devmem.path", PCI_PATH_DEVMEM_DEVICE, "Path to the /dev/mem device");
+  physmem_init_config(a);
   pci_define_param(a, "mmio-conf1-ext.addrs", "", "Physical addresses of memory mapped Intel conf1 extended interface"); /* format: 0xaddr1/0xdata1,0xaddr2/0xdata2,... */
 }
 
@@ -238,7 +196,6 @@ static int
 detect(struct pci_access *a, char *addrs_param_name)
 {
   char *addrs = pci_get_param(a, addrs_param_name);
-  char *devmem = pci_get_param(a, "devmem.path");
 
   if (!*addrs)
     {
@@ -252,13 +209,13 @@ detect(struct pci_access *a, char *addrs_param_name)
       return 0;
     }
 
-  if (access(devmem, R_OK | W_OK))
+  if (physmem_access(a, 1))
     {
-      a->debug("cannot access %s: %s", devmem, strerror(errno));
+      a->debug("cannot access physical memory: %s", strerror(errno));
       return 0;
     }
 
-  a->debug("using %s with %s", devmem, addrs);
+  a->debug("using with %s", addrs);
   return 1;
 }
 
@@ -288,11 +245,9 @@ conf1_init(struct pci_access *a)
 {
   char *addrs_param_name = get_addrs_param_name(a);
   char *addrs = pci_get_param(a, addrs_param_name);
-  char *devmem = pci_get_param(a, "devmem.path");
-
-  pagesize = sysconf(_SC_PAGESIZE);
-  if (pagesize < 0)
-    a->error("Cannot get page size: %s", strerror(errno));
+  struct mmio_access *macc;
+  struct physmem *physmem;
+  long pagesize;
 
   if (!*addrs)
     a->error("Option %s was not specified.", addrs_param_name);
@@ -300,20 +255,29 @@ conf1_init(struct pci_access *a)
   if (!validate_addrs(addrs))
     a->error("Option %s has invalid address format \"%s\".", addrs_param_name, addrs);
 
-  a->fd = open(devmem, O_RDWR | O_DSYNC); /* O_DSYNC bypass CPU cache for mmap() on Linux */
-  if (a->fd < 0)
-    a->error("Cannot open %s: %s.", devmem, strerror(errno));
+  physmem = physmem_open(a, 1);
+  if (!physmem)
+    a->error("Cannot open physcal memory: %s.", strerror(errno));
+
+  pagesize = physmem_get_pagesize(physmem);
+  if (pagesize <= 0)
+    a->error("Cannot get page size: %s.", strerror(errno));
+
+  macc = pci_malloc(a, sizeof(*macc));
+  macc->cache = NULL;
+  macc->physmem = physmem;
+  macc->pagesize = pagesize;
+  a->backend_data = macc;
 }
 
 static void
 conf1_cleanup(struct pci_access *a)
 {
-  if (a->fd < 0)
-    return;
+  struct mmio_access *macc = a->backend_data;
 
   munmap_regs(a);
-  close(a->fd);
-  a->fd = -1;
+  physmem_close(macc->physmem);
+  pci_mfree(macc);
 }
 
 static void
@@ -334,7 +298,7 @@ conf1_ext_read(struct pci_dev *d, int pos, byte *buf, int len)
   char *addrs_param_name = get_addrs_param_name(d->access);
   char *addrs = pci_get_param(d->access, addrs_param_name);
   volatile void *addr, *data;
-  off_t addr_reg, data_reg;
+  u64 addr_reg, data_reg;
 
   if (pos >= 4096)
     return 0;
@@ -348,19 +312,19 @@ conf1_ext_read(struct pci_dev *d, int pos, byte *buf, int len)
   if (!mmap_regs(d->access, addr_reg, data_reg, pos&3, &addr, &data))
     return 0;
 
-  writel(0x80000000 | ((pos & 0xf00) << 16) | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos & 0xfc), addr);
-  readl(addr); /* write barrier for address */
+  physmem_writel(0x80000000 | ((pos & 0xf00) << 16) | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos & 0xfc), addr);
+  physmem_readl(addr); /* write barrier for address */
 
   switch (len)
     {
     case 1:
-      buf[0] = readb(data);
+      buf[0] = physmem_readb(data);
       break;
     case 2:
-      ((u16 *) buf)[0] = readw(data);
+      ((u16 *) buf)[0] = physmem_readw(data);
       break;
     case 4:
-      ((u32 *) buf)[0] = readl(data);
+      ((u32 *) buf)[0] = physmem_readl(data);
       break;
     }
 
@@ -382,7 +346,7 @@ conf1_ext_write(struct pci_dev *d, int pos, byte *buf, int len)
   char *addrs_param_name = get_addrs_param_name(d->access);
   char *addrs = pci_get_param(d->access, addrs_param_name);
   volatile void *addr, *data;
-  off_t addr_reg, data_reg;
+  u64 addr_reg, data_reg;
 
   if (pos >= 4096)
     return 0;
@@ -396,19 +360,19 @@ conf1_ext_write(struct pci_dev *d, int pos, byte *buf, int len)
   if (!mmap_regs(d->access, addr_reg, data_reg, pos&3, &addr, &data))
     return 0;
 
-  writel(0x80000000 | ((pos & 0xf00) << 16) | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos & 0xfc), addr);
-  readl(addr); /* write barrier for address */
+  physmem_writel(0x80000000 | ((pos & 0xf00) << 16) | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos & 0xfc), addr);
+  physmem_readl(addr); /* write barrier for address */
 
   switch (len)
     {
     case 1:
-      writeb(buf[0], data);
+      physmem_writeb(buf[0], data);
       break;
     case 2:
-      writew(((u16 *) buf)[0], data);
+      physmem_writew(((u16 *) buf)[0], data);
       break;
     case 4:
-      writel(((u32 *) buf)[0], data);
+      physmem_writel(((u32 *) buf)[0], data);
       break;
     }
 
@@ -421,7 +385,7 @@ conf1_ext_write(struct pci_dev *d, int pos, byte *buf, int len)
    * Correct way is to issue CPU instruction for full hw sync barrier but gcc
    * does not provide any (builtin) function yet.
    */
-  readl(addr);
+  physmem_readl(addr);
 
   return 1;
 }
diff --git a/lib/physmem-access.h b/lib/physmem-access.h
new file mode 100644 (file)
index 0000000..a4e9744
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ *      The PCI Library -- Compiler-specific wrappers for memory mapped I/O
+ *
+ *      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
+ */
+
+/*
+ * FIXME
+ * Unfortunately gcc does not provide architecture independent way to read from
+ * or write to memory mapped I/O. The best approximation is to use volatile and
+ * for the write operation follow it by the read operation from the same address.
+ */
+
+static inline void
+physmem_writeb(unsigned char value, volatile void *ptr)
+{
+  *(volatile unsigned char *)ptr = value;
+}
+
+static inline void
+physmem_writew(unsigned short value, volatile void *ptr)
+{
+  *(volatile unsigned short *)ptr = value;
+}
+
+static inline void
+physmem_writel(u32 value, volatile void *ptr)
+{
+  *(volatile u32 *)ptr = value;
+}
+
+static inline unsigned char
+physmem_readb(volatile void *ptr)
+{
+  return *(volatile unsigned char *)ptr;
+}
+
+static inline unsigned short
+physmem_readw(volatile void *ptr)
+{
+  return *(volatile unsigned short *)ptr;
+}
+
+static inline u32
+physmem_readl(volatile void *ptr)
+{
+  return *(volatile u32 *)ptr;
+}
diff --git a/lib/physmem-posix.c b/lib/physmem-posix.c
new file mode 100644 (file)
index 0000000..664ec48
--- /dev/null
@@ -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)((1ULL << (sizeof(off_t) * CHAR_BIT - 1)) - 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);
+}
diff --git a/lib/physmem.h b/lib/physmem.h
new file mode 100644 (file)
index 0000000..46ee021
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ *      The PCI Library -- Physical memory mapping API
+ *
+ *      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
+ */
+
+struct physmem;
+
+void physmem_init_config(struct pci_access *a);
+int physmem_access(struct pci_access *a, int w);
+struct physmem *physmem_open(struct pci_access *a, int w);
+void physmem_close(struct physmem *physmem);
+long physmem_get_pagesize(struct physmem *physmem);
+void *physmem_map(struct physmem *physmem, u64 addr, size_t length, int w);
+int physmem_unmap(struct physmem *physmem, void *ptr, size_t length);